Skip to content

feat(kubevirt): add tool for QEMU guest agent access#811

Open
codingben wants to merge 2 commits intocontainers:mainfrom
codingben:add-guest-info
Open

feat(kubevirt): add tool for QEMU guest agent access#811
codingben wants to merge 2 commits intocontainers:mainfrom
codingben:add-guest-info

Conversation

@codingben
Copy link
Copy Markdown
Contributor

@codingben codingben commented Feb 25, 2026

Implements vm_guest_info tool to retrieve information from inside running VMs via QEMU guest agent without requiring SSH credentials.

Assisted-By: Claude noreply@anthropic.com

@codingben
Copy link
Copy Markdown
Contributor Author

/cc @lyarwood @ksimon1 @manusa @Cali0707

description: "Use vm_guest_info to audit which users are currently logged into VMs for security compliance"
steps:
setup:
inline: |-
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you please use new format of tasks as e.g. we are using here: #756?

Copy link
Copy Markdown
Contributor

@lyarwood lyarwood left a comment

Choose a reason for hiding this comment

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

Lets start with the evals, the use cases here are far too high level and model dependant for now. Can you simplify these and break them out into their own commits before any tooling is introduced.

echo " - User 'admin' logged in at 2024-02-25 14:30 ✓"
echo " - User 'unknown_user' logged in at 2024-02-25 03:00 ⚠ Investigate!"
echo ""
echo "✓ Security audit eval complete"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does the judge actually use this? If not it's just slop output that's not asserting anything.

kubectl delete namespace "$NS" --ignore-not-found
prompt:
inline: |
As part of a security compliance audit, you need to check who is currently logged into the production VirtualMachine "prod-app" in the ${EVAL_NAMESPACE:-vm-test} namespace.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like idea of eventually testing use cases like this but we really need to start with simple building blocks. Something like "list defined users in the VM" and asserting the returned list etc given the image used.

kubectl delete namespace "$NS" --ignore-not-found
prompt:
inline: |
A user reports that they cannot connect to the web server running inside the VirtualMachine named "web-server" in the ${EVAL_NAMESPACE:-vm-test} namespace.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Again just simplify and fetch and assert the IP?

Add five simple evaluation tasks that test basic vm_guest_info functionality:
- get-vm-filesystems: Get filesystem information from inside a VM
- get-vm-ip-address: Get IP address from inside the guest OS
- get-vm-os-info: Get OS name and version from a VM
- list-vm-users: List currently logged-in users in a VM
- vm-guest-info: General test for retrieving guest agent information

These evals focus on testing the basic building blocks rather than
high-level use cases, making them more reliable and model-independent.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Ben Oukhanov <boukhanov@redhat.com>
Add new vm_guest_info tool that enables querying information from inside
VirtualMachines using the QEMU guest agent, without requiring SSH access
or credentials.

The tool supports querying:
- os: Operating system information (name, version, kernel, hostname)
- filesystem: Mounted filesystems and disk usage
- network: Network interfaces and IP addresses
- users: Currently logged-in users and sessions

This provides a secure way to gather runtime information from VMs for
monitoring, troubleshooting, and compliance purposes.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Ben Oukhanov <boukhanov@redhat.com>
@codingben
Copy link
Copy Markdown
Contributor Author

@ksimon1 I'll address it. @lyarwood Does it looks better now?


// getGuestOSInfo retrieves operating system information from the guest agent
func getGuestOSInfo(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string) (map[string]any, error) {
gvr := schema.GroupVersionResource{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This GVR is defined 4x times in this file. Can you export it as package variable?


// Collect all info types, but don't fail if one is unavailable
osInfo, err := getGuestOSInfo(ctx, dynamicClient, namespace, name)
if err == nil {
Copy link
Copy Markdown
Contributor

@ksimon1 ksimon1 Mar 20, 2026

Choose a reason for hiding this comment

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

Nit - I would prefer here the normal go error handling

if err != nil{
...
} else {
...
}

result[k] = v
}
} else {
result["guestOSInfo"] = map[string]string{"error": err.Error()}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are you saving here the error, and on line 261 you are replacing it with general error? Would it make sense to create error from returned errors?


// getAllGuestInfo retrieves all available guest agent information
func getAllGuestInfo(ctx context.Context, dynamicClient dynamic.Interface, namespace, name string) (map[string]any, error) {
result := make(map[string]any)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it make sense to create regular struct instead of map[string]any?

}

// If all failed, return an error
if len(result) == 4 &&
Copy link
Copy Markdown
Contributor

@ksimon1 ksimon1 Mar 20, 2026

Choose a reason for hiding this comment

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

If just e.g. 1 guest info query fails do we want to still capture it as success?

})
s.Nilf(err, "call tool failed %v", err)
s.Truef(toolResult.IsError, "expected call tool to fail for non-existent VM")
s.Contains(toolResult.Content[0].(*mcp.TextContent).Text, "VirtualMachineInstance not found")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should this not say VirtualMachine not found. There is a distinct difference between a VirtualMachine and VirtualMachineInstance. One can start a VMI without a matching VM, but the description here say no VM, not no VMI (which can be either, not running VM, or no VMI)

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.

4 participants