Skip to content

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Mar 29, 2025

Summary by CodeRabbit

  • New Features

    • Introduced asynchronous operations for virtual machine domain management, enabling smoother domain destruction and removal.
    • Added a new shell script for Docker-based integration testing across multiple architectures.
    • Added new methods for domain management in the hypervisor context, including domain destruction and undefining.
    • Introduced a Domain class for comprehensive management of virtual machine instances.
    • Added a new GitHub Actions workflow for automated Docker integration tests across multiple architectures.
  • Enhancements

    • Improved Docker container configuration with a secure non-root user setup for safer deployments.
    • Expanded integration tests across multiple architectures and enhanced error handling to provide clearer feedback and improved reliability.
    • Enhanced XML serialization and deserialization processes for domain configurations, improving robustness against edge cases.
    • Updated testing framework to utilize Vitest, replacing previous testing tools and enhancing coverage reporting.
    • Added detailed documentation for several interfaces and enums to improve clarity.
    • Updated README with new badges and installation instructions, along with a new "Development" section.
  • Chores

    • Updated CI and dependency management to boost build stability and overall system consistency.
    • Introduced a new testing configuration for Vitest to streamline test execution and coverage reporting.
    • Updated system requirements in package management for better compatibility.
    • Modified .gitignore to include new entries for coverage and test artifacts.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 29, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

The pull request introduces extensive modifications across continuous integration, Docker configurations, domain management APIs, and testing suites. The workflow now caches additional packages and runs Docker integration tests, while the Dockerfile adopts a new base image and enhanced libvirt settings with a non-root user. Domain description interfaces and XML serialization have been expanded, and legacy native bindings have been removed and replaced with streamlined exports. New asynchronous operations for domain destruction and undefining have been implemented in C++ and exposed via updated Hypervisor and Domain classes. Several new tests and configuration improvements further validate the changes.

Changes

File(s) Change Summary
.github/workflows/main.yml, Dockerfile, scripts/test-docker.sh Updated CI/CD workflow to cache extra packages, add Docker Buildx/QEMU setup, and run multi-arch integration tests; Dockerfile now uses a new base image, minimal packages, non-root user, and explicit libvirt configurations.
lib/domain-desc.ts, lib/domain-xml.ts, lib/get-bindings.ts, lib/index.ts Modified domain interfaces with additional optional properties and loader configuration; updated serialization/deserialization logic; removed legacy native bindings and streamlined export structure.
lib/types.ts, lib/error.ts Revised type definitions with enhanced JSDoc comments; introduced LibvirtError class and standardized error handling with new helper functions.
lib/domain.ts, lib/hypervisor.ts Added new Domain and Hypervisor classes with comprehensive asynchronous methods for managing VM operations including creation, shutdown, destruction, and undefining.
src/domain.h, src/hypervisor-domain.cc, src/hypervisor.cc, src/hypervisor.h Implemented new asynchronous operations for domain destruction and undefining, adding dedicated worker classes and exposing them via new Hypervisor methods with friend class access.
__tests__/**/*.{test,spec}.ts, vitest.config.ts Introduced extensive test suites covering domain lifecycle, cleanup, listing, error handling, and hypervisor functionality; added Vitest configuration for comprehensive testing and coverage reporting.
package.json, tsconfig.json, .gitignore Updated test scripts and devDependencies (switch from Mocha to Vitest), modified system requirements, disabled incremental compilation, and added new ignore rules for coverage and test artifacts.
lib/domain-builder.spec.ts New tests validating the DomainBuilder functionality.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant H as Hypervisor
    participant W as Worker
    participant D as Domain

    %% Domain Destruction Flow
    C->>H: DomainDestroy(request)
    H->>W: Create DomainDestroyWorker(callback, promise, domain)
    W->>D: virDomainDestroy()
    D-->>W: Return status/error
    W->>H: Resolve promise with result
    H-->>C: DomainDestroy result

    %% Domain Undefine Flow
    C->>H: DomainUndefine(request)
    H->>W: Create DomainUndefineWorker(callback, promise, domain)
    W->>D: virDomainUndefine()
    D-->>W: Return status/error
    W->>H: Resolve promise with result
    H-->>C: DomainUndefine result
Loading

Possibly related PRs

  • feat: build libvirt to libvirt not virt #22: The changes in the main PR focus on enhancing the GitHub Actions workflow for caching APT packages and setting up Docker Buildx, while the retrieved PR modifies the build process in the same workflow file by adding a verification step after the build command; thus, they are related at the code level.
  • feat!/major api improvements #37: The changes in the main PR are directly related to those in the retrieved PR, as both involve modifications to the same workflow file and Dockerfile, specifically focusing on caching APT packages and the setup of Docker Buildx.
  • feat: build updates #9: The changes in the main PR regarding the caching of APT packages and the setup of Docker Buildx are related to the modifications in the retrieved PR, which also involves updates to the workflow for caching APT packages and transitioning to pnpm for package management. Both PRs focus on enhancing the workflow configuration in the .github/workflows/main.yml file.

Poem

I'm a bouncy bunny, hopping through the code,
Skipping over errors on this bright new road.
CI flows and Docker dreams, a clever, crafted art,
Domains and tests, a joyous start.
With hops and nibbles, I celebrate each change so bold!
🐇🌟


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between b5e6e4e and 98e1957.

📒 Files selected for processing (1)
  • .github/workflows/integration-test.yml (1 hunks)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 3

🔭 Outside diff range comments (2)
lib/domain-xml.ts (2)

89-125: ⚠️ Potential issue

Deserialization only handles the first loader object, creating mismatch with serialization arrays.

While the serialization can produce an array of loader elements, the deserialization only extracts the first element. This inconsistency can lead to data loss if multiple loaders are serialized. Consider supporting an array in deserialization, or make it explicit that only one loader is supported.

Possible fix:

-    if (os.loader?.[0]) {
-      osDesc.loader = { };
-      ...
-    }
+    if (os.loader && os.loader.length > 0) {
+      if (os.loader.length === 1) {
+        // Single loader object
+        osDesc.loader = { ... };
+      } else {
+        // Multiple loader objects
+        osDesc.loader = os.loader.map((loaderObj: any) => {
+          const loaderRef: any = {};
+          // Populate loaderRef similarly
+          return loaderRef;
+        });
+      }
+    }

369-404: 🛠️ Refactor suggestion

Wrap switch-case declarations in blocks.

Local declarations like const emulatorDesc can leak into subsequent cases, violating lint rules. Wrapping each case body in braces resolves the noSwitchDeclarations lint error and clarifies scope.

Proposed change:

-        case 'emulator':
-          const emulatorDesc = deviceDesc.emulator;
-          if (emulatorDesc.value) {
-            domain.devices.emulator.push({
-              _: emulatorDesc.value
-            });
-          }
-          break;
+        case 'emulator': {
+          const emulatorDesc = deviceDesc.emulator;
+          if (emulatorDesc.value) {
+            domain.devices.emulator.push({
+              _: emulatorDesc.value
+            });
+          }
+          break;
+        }

         ...

-        case 'console':
-          const consoleDesc = deviceDesc.console;
-          domain.devices.console.push({
-            $: {
-              type: consoleDesc.type
-            }
-          });
-          break;
+        case 'console': {
+          const consoleDesc = deviceDesc.console;
+          domain.devices.console.push({
+            $: {
+              type: consoleDesc.type
+            }
+          });
+          break;
+        }

         ...

-        case 'acpi':
-          domain.devices.acpi.push({});
-          break;
+        case 'acpi': {
+          domain.devices.acpi.push({});
+          break;
+        }
🧰 Tools
🪛 Biome (1.9.4)

[error] 369-369: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 388-388: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🧹 Nitpick comments (15)
.github/workflows/main.yml (1)

45-49: Proper service initialization for libvirt.

The addition of these steps ensures that the libvirt service is running and properly configured for the tests to execute correctly. This is essential for the hypervisor management functionality.

However, consider quoting the $USER variable on line 48 to prevent potential issues with shell expansion.

- sudo usermod -a -G libvirt $USER
+ sudo usermod -a -G libvirt "$USER"
🧰 Tools
🪛 actionlint (1.7.4)

46-46: shellcheck reported issue in this script: SC2086:info:2:28: Double quote to prevent globbing and word splitting

(shellcheck)

scripts/test-docker.sh (2)

49-53: Verify Docker buildx installation success.

The script attempts to install Docker buildx if not found, but doesn't verify if the installation was successful before proceeding with the tests.

if ! docker buildx version >/dev/null 2>&1; then
    echo -e "${YELLOW}Docker buildx not found. Installing...${NC}"
    docker buildx install
+    if ! docker buildx version >/dev/null 2>&1; then
+        echo -e "${RED}Failed to install Docker buildx. Exiting.${NC}"
+        exit 1
+    fi
fi

56-56: Unused test-artifacts directory.

The script creates a directory for test artifacts but doesn't appear to use it. Consider either removing it or documenting its purpose.

-# Create a temporary directory for test artifacts
-mkdir -p test-artifacts
+# If you need to store test artifacts, uncomment the line below
+# mkdir -p test-artifacts
.github/workflows/docker-integration.yml (1)

74-74: Add a newline at the end of the file and remove trailing spaces.

Lint errors indicate missing end-of-file newline and trailing spaces.

Apply this diff:

-          retention-days: 7 
+          retention-days: 7
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 74-74: no new line character at the end of file

(new-line-at-end-of-file)


[error] 74-74: trailing spaces

(trailing-spaces)

lib/domain-xml.ts (1)

55-82: Consider unifying loader serialization logic.

Presently, the code handles loader arrays and single objects separately, resulting in duplicated logic. Refactoring to a helper function or single code path could reduce complexity and improve maintainability.

__tests__/integration.test.ts (1)

190-309: Evaluate parallel test runs for domain naming conflicts.

Integration tests with a fixed domain name (TEST_VM_NAME) and a shared image path can fail if multiple workflows run concurrently. Consider using unique domain names or ephemeral resources.

lib/domain-desc.ts (3)

29-30: Ensure alignment with potential additional firmware types.

While 'efi' and 'bios' are common, there may be alternate firmware/boot loader specifications. If upstream changes or more variants (e.g., custom EFIs) are needed in the future, consider making this property more extensible.


31-39: Validate consistency of union structure for loader.

The union of a single object vs. an array of objects is flexible but can complicate usage. If the architecture allows multiple loaders consistently, consider always using an array—possibly of length one or more—to reduce branching logic for consumers.


147-149: Clarify intended usage of the acpi device.

acpi: Record<string, never> indicates an empty config object. If additional ACPI-related properties might be required in the future, consider defining placeholders or making the type more extensible now.

Dockerfile (4)

7-19: Consider a more minimalist or pinned approach for packages.

You’re installing many QEMU and libvirt components without version pinning. While this helps keep the environment fresh, it might lead to nondeterministic builds if package versions shift.


32-33: Consider caching pnpm installation.

Installing pnpm globally each time can slow builds. Caching or leveraging an official Node image with pnpm built-in could speed up CI/CD.


35-36: Evaluate multi-stage builds for faster, smaller images.

By building in one stage and copying only the final artifacts, you can reduce the final Docker image size and isolate dev dependencies from runtime.


52-52: Reassess running multiple processes in a single container.

libvirtd --daemon plus npm test in one container can complicate logs and persistent processes. Consider using a separate service container or a single entrypoint with supervisor if you need both processes concurrently.

lib/types.ts (2)

8-37: Ensure promise rejections are handled.

All methods return Promises. Confirm that callers handle failures (e.g., connection errors), and consider adding doc comments specifying possible error states.


39-46: Document the lifecycle of HypervisorClass.

Mention how HypervisorClass is typically used (e.g., via a native binding). This helps maintainers and users understand the injection/creation pattern.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39027a6 and 62003f2.

📒 Files selected for processing (11)
  • .github/workflows/docker-integration.yml (1 hunks)
  • .github/workflows/main.yml (1 hunks)
  • Dockerfile (1 hunks)
  • __tests__/integration.test.ts (1 hunks)
  • lib/domain-desc.ts (3 hunks)
  • lib/domain-xml.ts (4 hunks)
  • lib/get-bindings.ts (1 hunks)
  • lib/index.ts (1 hunks)
  • lib/types.ts (2 hunks)
  • package.json (1 hunks)
  • scripts/test-docker.sh (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
lib/get-bindings.ts (1)
lib/types.ts (1)
  • HypervisorClass (43-45)
lib/types.ts (2)
lib/index.ts (3)
  • ConnectListAllDomainsFlags (13-13)
  • Domain (12-12)
  • DomainGetXMLDescFlags (14-14)
lib/get-bindings.ts (2)
  • ConnectListAllDomainsFlags (30-47)
  • DomainGetXMLDescFlags (49-54)
🪛 YAMLlint (1.35.1)
.github/workflows/docker-integration.yml

[error] 74-74: no new line character at the end of file

(new-line-at-end-of-file)


[error] 74-74: trailing spaces

(trailing-spaces)

🪛 Biome (1.9.4)
lib/domain-xml.ts

[error] 369-369: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

lib/types.ts

[error] 135-135: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🪛 actionlint (1.7.4)
.github/workflows/main.yml

46-46: shellcheck reported issue in this script: SC2086:info:2:28: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (12)
.github/workflows/main.yml (1)

42-42: Good addition of QEMU package to cache.

Adding qemu-system to the cached packages will improve workflow execution times by ensuring this dependency is available for subsequent runs.

lib/get-bindings.ts (1)

11-11: Improved type naming from HypervisorConstructor to HypervisorClass.

This change improves code clarity by using a more descriptive and intuitive type name that better reflects the purpose of the interface - a class for creating hypervisor instances.

Also applies to: 19-19

scripts/test-docker.sh (2)

1-14: Good initialization of Docker test script with clear architecture targets.

The script is well-structured with clear documentation of supported architectures and color codes for improved output readability.


15-44: Well-designed test execution function with appropriate error handling.

The run_tests function properly builds and executes Docker containers for testing with the required privileges and volume mounts for libvirt. The error handling is appropriate with a non-zero exit code on failure.

package.json (1)

29-31: Well-structured test script separation.

Excellent reorganization of the test scripts into unit and integration tests. This separation provides better flexibility by allowing developers to run specific test suites as needed while maintaining the ability to run all tests together.

.github/workflows/docker-integration.yml (2)

13-33: Matrix enumeration looks good!

The matrix strategy effectively tests various OS and architecture combinations. This approach ensures broad coverage for Docker builds and offers confidence in multi-platform support.


68-74:

Details

❓ Verification inconclusive

Verify artifact directory before upload.

It's not immediately clear whether test-artifacts/ is guaranteed to exist across all runs. If no artifacts are generated, the upload step might fail silently. Consider creating or checking the directory conditionally.


🏁 Script executed:

#!/bin/bash
# Verify that 'test-artifacts/' is created or referenced in the repository
fd test-artifacts

Length of output: 19


I'm not seeing any concrete evidence that the test-artifacts/ directory is created before its use in the upload step. The fd test-artifacts command produced no output, which is inconclusive. To get further clarity, please run a script that searches for references to the creation or use of the test-artifacts directory (for example, looking for commands like mkdir test-artifacts or other mentions of it) across the repository.

Below is a shell script that might help verify this more thoroughly:

#!/bin/bash
echo "Searching for commands that create the test-artifacts directory (e.g., mkdir):"
rg -n "mkdir.*test-artifacts" .

echo "Searching for any reference to 'test-artifacts' in the repository:"
rg -n "test-artifacts" .

Once you verify whether the directory is created in any workflow or script, please update accordingly:

  • If no creation is found: Consider adding a conditional step to create (or check) the directory before running the upload action to prevent silent failures.
  • If the directory is created elsewhere: Please confirm that its creation is reliably executed on all runs.

Next Action:
Please run the script above to manually verify how the test-artifacts/ directory is handled across the codebase and confirm the expected behavior.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 74-74: no new line character at the end of file

(new-line-at-end-of-file)


[error] 74-74: trailing spaces

(trailing-spaces)

__tests__/integration.test.ts (1)

16-47:

Details

❓ Verification inconclusive

Confirm that the firmware field is set for relevant architectures.

The code references archConfig.firmware?.code and archConfig.firmware?.vars, but getArchConfig() never sets these properties. This leads to unimplemented firmware copying for non-Apple architectures and potential dead code paths. Verify if you intend to add or remove firmware logic.


🏁 Script executed:

#!/bin/bash
# Check for any references to 'firmware' in the codebase outside of 'getArchConfig' 
rg "firmware"

Length of output: 1153


Firmware configuration is incomplete: Please clarify intended behavior

  • The integration test (in __tests__/integration.test.ts) accesses archConfig.firmware?.code and archConfig.firmware?.vars, but the getArchConfig() function never provides a firmware property.
  • Additionally, the type definition in lib/domain-desc.ts declares firmware differently (firmware?: 'efi' | 'bios'), which is inconsistent with the object structure expected by the integration test.
  • Please confirm whether firmware support should be implemented in getArchConfig() for relevant architectures, or if the firmware-related checks and references in the tests need removal/adjustment.
lib/domain-desc.ts (2)

41-45: Check the interplay of nvram and firmware.

It’s common for nvram to be relevant primarily under certain firmware conditions (e.g., EFI). Ensure that the rest of the codebase properly accounts for scenarios where nvram is present but firmware is bios, and vice versa.


105-105: Confirm usage and testing for the new 'qemu' option.

Expanding type to 'qemu' is a sensible extension. Verify all domain creation, management, and validation logic to ensure it supports 'qemu' consistently.

Dockerfile (2)

2-2: Confirm Node.js 20 compatibility with QEMU and libvirt.

Switching from node:22 to node:20 may affect library compatibility, especially with system libraries. Verify no unexpected issues arise from the older Node version.


21-26: Validate group existence before adding the new user.

Some slim images might not have the libvirt or kvm groups pre-defined. Double-check that group creation or existence checks are properly handled for a robust build on all systems.

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 (3)
__tests__/integration.test.ts (3)

55-57: Consider conditionally skipping tests if QEMU is missing.
Currently, the test immediately throws an error when QEMU is not installed. For CI pipelines or local dev environments lacking QEMU, you may prefer skipping or gracefully handling these tests rather than failing outright.


70-92: Revisit broad “ignore errors” approach in disk cleanup.
Multiple try/catch blocks absorb any potential errors during disk/NVRAM cleanup. While ignoring specific known errors may be intentional (e.g., the disk does not exist), masking other exceptions can hinder identifying real issues. Consider logging errors at a more visible level (e.g., warnings) and only ignoring truly benign conditions.


107-119: Improve shutdown error handling for better diagnostic clarity.
Ignoring errors during shutdown might mask genuine failures or concurrency issues. Even if it is expected to fail without an OS, capturing and logging the error details more explicitly could assist in troubleshooting and provide clearer insights into abnormal shutdown sequences.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d74d868 and 2e28759.

📒 Files selected for processing (6)
  • __tests__/integration.test.ts (1 hunks)
  • lib/types.ts (2 hunks)
  • src/domain.h (1 hunks)
  • src/hypervisor-domain.cc (1 hunks)
  • src/hypervisor.cc (1 hunks)
  • src/hypervisor.h (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
src/hypervisor.cc (1)
src/hypervisor-domain.cc (2)
  • DomainDestroy (723-743)
  • DomainDestroy (723-723)
src/hypervisor-domain.cc (2)
src/worker.cc (2)
  • SetVirError (12-17)
  • SetVirError (12-12)
src/hypervisor-connect.cc (2)
  • dummyCallback (15-19)
  • dummyCallback (15-15)
🪛 Biome (1.9.4)
lib/types.ts

[error] 136-136: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🔇 Additional comments (6)
src/domain.h (1)

44-44: Friend class addition correctly follows established pattern.

The addition of DomainDestroyWorker as a friend class allows it to access the private domainPtr member, which is necessary for the domain destruction operation. This follows the same pattern used for other worker classes in this file.

src/hypervisor.h (1)

69-69: Method declaration appropriately extends domain management capabilities.

The DomainDestroy method declaration is correctly placed among other domain management methods and follows the same signature pattern as similar methods like DomainShutdown.

src/hypervisor.cc (1)

38-38: Instance method registration follows established naming conventions.

The domainDestroy instance method is properly registered and follows the camelCase naming convention used for JavaScript-exposed methods. The registration is correctly placed among other domain management methods.

src/hypervisor-domain.cc (2)

701-721: DomainDestroyWorker implementation follows established worker pattern.

The DomainDestroyWorker class correctly implements the worker pattern used throughout the codebase:

  • Inherits from Worker base class
  • Takes appropriate parameters in constructor
  • Implements Execute() to interact with libvirt API
  • Properly handles error cases

This maintains consistency with other similar worker implementations in the file.


723-743: DomainDestroy method implementation is consistent with other domain operations.

The implementation follows the established pattern for domain operations:

  1. Sets up environment and promise handling
  2. Validates input parameters
  3. Unwraps the Domain object
  4. Creates and queues the appropriate worker
  5. Returns the promise for asynchronous resolution

This ensures that the new functionality integrates well with the existing architecture.

lib/types.ts (1)

136-136: Avoid using empty interfaces.
This comment mirrors a past review indicating that an empty interface is effectively {}. Switching to a type alias (e.g., type Domain = Record<string, never>;) or adding domain-specific details helps maintain clarity and consistency.

-export interface Domain {}
+export type Domain = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 136-136: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

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 (14)
tsconfig.json (1)

4-4: Clarify the Incremental Compilation Setting Comment

The configuration sets "incremental": false, which disables incremental compilation, but the inline comment still reads "Enable incremental compilation." This creates a contradiction. Please update the comment to accurately reflect that incremental compilation is disabled (or update the value if the intent was different).

src/domain.h (1)

44-47: Ensure new friend classes are tested.

Adding DomainDestroyWorker and DomainUndefineWorker as friend classes is fine if they require direct access to internal members. Verify that these new classes are covered by tests to ensure reliable domain destroy/undefine functionalities.

lib/domain.ts (1)

3-58: Consider removing the any type for hypervisor.

The domain wrapper’s asynchronous methods delegate logic to the hypervisor. Explicitly typing this property, for example by using a forward type reference (import type { Hypervisor } from './hypervisor.js';), could improve type safety.

- private hypervisor: any;
+ private hypervisor: Hypervisor;  // or a suitable interface/type
lib/hypervisor.ts (1)

15-36: Robust error handling.

Converting all errors into LibvirtError for uniform handling is a solid approach. As a minor enhancement, consider checking if the error is already a LibvirtError to avoid re-wrapping:

if (error instanceof LibvirtError) {
    throw error;
} else if (error instanceof Error) {
    ...
}
__tests__/integration.test.ts (5)

16-47: Refine architecture detection logic.
In getArchConfig, you are branching twice on process.platform and process.arch, but the code paths for Darwin vs. other OS appear nearly duplicated aside from the emulator paths. Consider extracting shared logic (e.g., architecture strings and machine types) into a separate function or map to reduce duplication.

 function getArchConfig(): { arch: string; machine: string; firmware?: { code: string; vars: string }; emulator: string } {
   if (process.platform === 'darwin') {
     if (process.arch === 'arm64') {
       return {
         arch: 'aarch64',
         machine: 'virt',
-        emulator: '/opt/homebrew/bin/qemu-system-aarch64'
+        emulator: findQemuEmulator('darwin', 'arm64') // Example helper
       };
     } else {
       return {
         arch: 'x86_64',
         machine: 'q35',
-        emulator: '/opt/homebrew/bin/qemu-system-x86_64'
+        emulator: findQemuEmulator('darwin', 'x64') // Example helper
       };
     }
   } else {
     // ...
   }
 }

50-68: Confirm synchronous file checks won’t block the test flow.
verifyQemuInstallation relies on existsSync calls that block the event loop. Although acceptable for a small integration test, large-scale tests might see performance issues. Consider an asynchronous approach if the test suite grows.


70-93: Ensure safe handling for leftover lock files.
cleanupDiskImage does a best-effort lock removal using execSync(qemu-img info ...). Although ignoring errors is fine in tests, it might be useful to log them with a distinct message if ephemeral lock cleanup fails repeatedly, to aid debugging on CI environments.


161-184: Avoid large logic in lifecycle hooks.
The before hook is doing significant domain management and QEMU verifications. While it’s valid, consider splitting these steps or re-checking them in each test for clarity and fewer cross-test dependencies.


431-448: Verify multiple non-existent domain variations.
The test 'should handle errors when trying to undefine a non-existent domain' checks a single non-existent name. Consider adding a test scenario for an invalid domain object or empty string to ensure libvirt errors are handled consistently.

src/hypervisor-domain.cc (2)

701-743: Verify domain pointer validity before destruction.
In DomainDestroy, there is no explicit check for a NULL domainPtr before calling virDomainDestroy. While the call itself may fail gracefully, consider logging or throwing a friendlier error if domainPtr is unexpectedly null.

int destroy = 0;
if (domain->domainPtr == nullptr) {
-   destroy = virDomainDestroy(domain->domainPtr);
+   SetError("Domain pointer is null, cannot destroy");
}
else {
  destroy = virDomainDestroy(domain->domainPtr);
}

749-787: Add warnings for persistent domains.
DomainUndefine can remove persistent domain definitions. If the domain is still active or partially configured, it may cause confusion during subsequent commands. Consider logging a warning that the domain is being removed while still active.

Would you like help implementing a quick check for an active domain before calling virDomainUndefine?

lib/types.ts (3)

8-18: Validate memory values in DomainInfo.
Consider clarifying that maxMem and memory are measured in KiB (the typical libvirt behavior). If you store them in bytes or MB in the rest of the codebase, the mismatch could cause confusion.


100-123: Avoid duplication of connect list flags.
ConnectListAllDomainsFlags is comprehensive. If new flags are introduced in libvirt, you’ll need to update manually. Alternatively, these flags could be loaded from the native library if exposed.

Would you like me to generate a snippet that attempts to read flags from libvirt’s headers or docs at build time?


136-139: Replace Domain = any with a more specific type if possible.
Using any forfeits type-checking benefits. If the domain shape will remain dynamic, consider using a more descriptive union or partial interface for future maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between bf8b112 and 2144db2.

📒 Files selected for processing (12)
  • __tests__/integration.test.ts (1 hunks)
  • lib/domain-desc.ts (6 hunks)
  • lib/domain.ts (1 hunks)
  • lib/get-bindings.ts (0 hunks)
  • lib/hypervisor.ts (1 hunks)
  • lib/index.ts (1 hunks)
  • lib/types.ts (3 hunks)
  • src/domain.h (1 hunks)
  • src/hypervisor-domain.cc (1 hunks)
  • src/hypervisor.cc (1 hunks)
  • src/hypervisor.h (3 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/get-bindings.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/hypervisor.cc
  • src/hypervisor.h
  • lib/domain-desc.ts
🧰 Additional context used
🧬 Code Definitions (3)
lib/hypervisor.ts (1)
lib/types.ts (8)
  • LibvirtError (141-159)
  • ConnectListAllDomainsFlags (103-120)
  • ConnectListAllDomainsFlags (122-122)
  • Domain (139-139)
  • DomainInfo (11-17)
  • DomainGetXMLDescFlags (127-132)
  • DomainGetXMLDescFlags (134-134)
  • NodeInfo (22-31)
src/hypervisor-domain.cc (3)
lib/domain.ts (1)
  • destroy (25-27)
src/worker.cc (2)
  • SetVirError (12-17)
  • SetVirError (12-12)
src/hypervisor-connect.cc (2)
  • dummyCallback (15-19)
  • dummyCallback (15-15)
__tests__/integration.test.ts (5)
lib/hypervisor.ts (1)
  • Hypervisor (7-233)
lib/types.ts (5)
  • Domain (139-139)
  • DomainState (63-72)
  • DomainState (74-74)
  • HypervisorOptions (4-6)
  • LibvirtError (141-159)
lib/domain.ts (1)
  • Domain (3-58)
lib/domain-desc.ts (1)
  • DomainDesc (103-150)
lib/domain-xml.ts (1)
  • domainDescToXml (300-412)
🔇 Additional comments (13)
lib/index.ts (3)

1-2: Exports look well-structured.

These lines ensure that all core types and constants are exposed for external use. There appears to be no overlap or duplication with other exports.


4-6: Single entry point for key classes is helpful.

Re-exporting Hypervisor and Domain at the index level centralizes imports and enhances discoverability. This fosters a better developer experience.


8-8: Domain utilities export is consistent.

Exporting domain-desc.js, domain-xml.js, and domain-builder.js here is consistent with your approach of providing a one-stop index for domain-related functionality. No conflicts detected.

lib/domain.ts (1)

1-2: Imports are appropriate.

Importing the domain-related types helps maintain strong typing for domain operations.

lib/hypervisor.ts (6)

7-13: Excellent constructor approach for native binding.

Using require for the native module within an ES module context is a practical solution. Ensure that the path '../build/Release/libvirt' is well-documented or configurable to support different build configurations.


38-79: Connection methods and domain listing appear correct.

The connectOpen/Close and connectListAllDomains methods properly handle promises and rethrow errors via handleError, promoting clarity in error reporting.


81-125: Domain creation and lookup methods are consistent.

Each method returns a Domain object, providing uniform access to domain functionality. This design choice simplifies domain management at the higher layers.


127-166: Asynchronous domain operations are well-structured.

Methods like domainSave, domainCreate, domainShutdown, domainDestroy, and domainUndefine consistently forward the native domain pointers. This pattern centralizes error handling and ensures a clean interface from the Domain class.


168-207: Domain information methods are straightforward.

Using consistent naming (domainGetInfo, domainGetID, etc.) is readable and intuitive, minimizing confusion.


209-232: Additional connect/node methods further enhance utility.

Providing methods for retrieving maximum VCPUs, hostname, and node info completes the hypervisor management toolset. Consider verifying test coverage for these methods to ensure they handle edge cases gracefully.

__tests__/integration.test.ts (1)

95-159: Guard against concurrency or multiple cleanup calls.
In cleanupDomain, you are performing multiple asynchronous steps (graceful shutdown, forced shutdown, undefine). If two cleanup calls ran concurrently, domain lookups or forcible shutdown attempts might race. Since integration tests typically run sequentially, this might be acceptable, but it’s worth noting if you plan parallel test execution in the future.

Could you confirm that these integration tests are always run serially on your CI so concurrency issues won’t arise?

lib/types.ts (2)

141-159: Ensure alignment of error details in LibvirtError.
You’re capturing code, domain, level, and up to three optional strings. Make sure these properties precisely mirror the fields from virError so usage in your code remains consistent.

Could you confirm that these are indeed all the fields you need from virError?


60-75:

Details

✅ Verification successful

Align domain states with official libvirt docs.
DomainState constants appear correct, but completeness and future changes may occur. If you prefer to track new states automatically, you might dynamically map them from libvirt constants at runtime. Otherwise, keep them updated whenever libvirt adds new domain states.


🌐 Web query:

Could you check the official libvirt documentation to confirm there are no newly added domain states beyond PMSUSPENDED?

💡 Result:

The official libvirt documentation, as reflected in the provided sources, confirms six primary domain states: running, idle, paused, in shutdown, shut off, crashed, and pmsuspended[1][2][14]. These states are consistently documented across various versions of the libvirt tools, including virsh, and are supported in recent resources like the Red Hat Enterprise Linux documentation and libvirt's API references[5][12][15].

Key Domain States:

  • Running: Actively executing on the hypervisor.
  • Idle: Not actively using CPU resources but still allocated resources.
  • Paused: Execution suspended, resources retained[1][2].
  • In shutdown: Gracefully stopping operations.
  • Shut off: Not running, either after shutdown or not started.
  • Crashed: Terminated unexpectedly without restart.
  • Pmsuspended: Suspended via guest power management (e.g., S3 sleep)[1][5][8].

Validation Against Sources:

  • The virsh manpage explicitly lists these states, with pmsuspended included[1].
  • Red Hat’s documentation for RHEL 7 and 6 reiterates these states, including pmsuspended[5][14].
  • GitHub discussions (e.g., issues in vagrant-libvirt and virt-manager) address handling pmsuspended but do not mention newer states[8][9][11].
  • The libvirt domain XML schema and Java API also align with these definitions[10][15].

No sources indicate newly added states beyond pmsuspended in the latest documentation as of March 2025. For robustness, always refer to the official libvirt domain states documentation for updates.

Citations:


Libvirt domain states verified – code aligns with the official documentation.

The current DomainState in lib/types.ts (lines 60–75) correctly reflects the states defined by libvirt up to PMSUSPENDED. Verification against the official documentation confirms that no new domain states have been added beyond those currently listed. For additional future-proofing, you might consider a dynamic mapping approach, but for now the explicit constants are correct.

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 (5)
lib/domain.ts (2)

28-30: Consider adding filename validation to prevent path traversal.

The save method accepts a filename parameter without validation. Consider adding validation to ensure the path is safe and doesn't allow for path traversal attacks.

async save(filename: string): Promise<void> {
+    // Validate filename to prevent path traversal
+    if (!filename || filename.includes('..')) {
+        throw new Error('Invalid filename');
+    }
    return this.hypervisor.domainSave(this, filename);
}

119-121: Consider using a getter instead of a method for internal access.

Since getNativeDomain is a simple accessor that returns an internal property, consider using a TypeScript getter property instead of a method. This would make the code more idiomatic.

-/**
- * Gets the native libvirt domain object.
- * This method is for internal use only.
- * @returns The native domain object
- */
-getNativeDomain(): NativeDomain {
-    return this.nativeDomain;
-}
+/**
+ * Gets the native libvirt domain object.
+ * This property is for internal use only.
+ * @returns The native domain object
+ */
+get nativeDomain(): NativeDomain {
+    return this.nativeDomain;
+}

Then update all references to domain.getNativeDomain() to domain.nativeDomain.

lib/hypervisor.ts (3)

12-23: Consider adding TypeScript type for the native hypervisor.

The nativeHypervisor property is typed as any, which reduces type safety. Consider creating a specific interface for the native hypervisor to improve type checking.

+/**
+ * Interface for the native libvirt hypervisor.
+ */
+interface NativeHypervisor {
+    connectOpen(): Promise<void>;
+    connectClose(): Promise<void>;
+    connectListAllDomains(flags?: number): Promise<any[]>;
+    // Add other methods as needed
+}

export class Hypervisor {
-    private nativeHypervisor: any;
+    private nativeHypervisor: NativeHypervisor;

    /**
     * Creates a new Hypervisor instance.
     * @param options - Connection options
     * @param options.uri - The URI to connect to the hypervisor (e.g., 'qemu:///system')
     */
    constructor(options: { uri: string }) {
        // Use require for native module since it's not an ES module
-        this.nativeHypervisor = new (require('../build/Release/libvirt').Hypervisor)(options);
+        this.nativeHypervisor = new (require('../build/Release/libvirt').Hypervisor)(options) as NativeHypervisor;
    }

31-52: Enhance error handling for edge cases.

The handleError method doesn't handle the case where error might be undefined or null. Also, the second branch assumes error is an object with a toString method.

private handleError(error: any): never {
+    if (error === undefined || error === null) {
+        throw new LibvirtError(
+            'Unknown error occurred',
+            -1,
+            -1,
+            -1
+        );
+    }
    if (error instanceof Error) {
        // If it's already an Error instance, convert it to LibvirtError
        const libvirtError = new LibvirtError(
            error.message,
            (error as any).code || -1,
            (error as any).domain || -1,
            (error as any).level || -1,
            (error as any).str1,
            (error as any).str2,
            (error as any).str3
        );
        throw libvirtError;
    }
    // If it's a string or something else, create a generic LibvirtError
    throw new LibvirtError(
-        error.toString(),
+        typeof error === 'object' && error !== null ? error.toString() : String(error),
        -1,
        -1,
        -1
    );
}

200-206: Add resource cleanup method.

The class doesn't provide a way to automatically clean up resources. Consider adding a method to explicitly close connections and release resources.

/**
 * Cleans up resources used by this hypervisor instance.
 * This should be called when the hypervisor is no longer needed.
 * @throws {LibvirtError} If cleanup fails
 */
async cleanup(): Promise<void> {
    try {
        // Close the connection if it's open
        return await this.connectClose();
    } catch (error) {
        this.handleError(error);
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 2144db2 and 3f8ca21.

📒 Files selected for processing (2)
  • lib/domain.ts (1 hunks)
  • lib/hypervisor.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
lib/domain.ts (3)
lib/index.ts (2)
  • Domain (6-6)
  • Hypervisor (5-5)
lib/types.ts (4)
  • Domain (139-139)
  • DomainGetXMLDescFlags (127-132)
  • DomainGetXMLDescFlags (134-134)
  • DomainInfo (11-17)
lib/hypervisor.ts (1)
  • Hypervisor (12-370)
lib/hypervisor.ts (2)
lib/types.ts (7)
  • LibvirtError (141-159)
  • ConnectListAllDomainsFlags (103-120)
  • ConnectListAllDomainsFlags (122-122)
  • Domain (139-139)
  • DomainInfo (11-17)
  • DomainGetXMLDescFlags (127-132)
  • DomainGetXMLDescFlags (134-134)
lib/domain.ts (1)
  • Domain (8-122)
🔇 Additional comments (5)
lib/domain.ts (3)

1-3: LGTM! Proper imports with extension for ES modules.

The imports are correctly specified with the .js extension, which is necessary for ES modules to work properly in Node.js. Additionally, the import from ./types.js properly aliases Domain to NativeDomain to avoid naming conflicts with the class being defined.


8-20: Well-structured domain class with proper encapsulation.

The Domain class follows good object-oriented design by encapsulating both the native domain object and the hypervisor instance. This design allows for a clean separation of concerns, where the Domain class provides a high-level API while delegating the actual work to the hypervisor.


37-39: LGTM! Method implementations follow a consistent pattern.

All methods consistently delegate to the hypervisor instance, which handles the actual operations and error management. This approach ensures a clean separation of concerns and makes the codebase easier to maintain.

Also applies to: 46-48, 55-57, 64-66, 74-76, 83-85, 92-94, 101-103, 110-112

lib/hypervisor.ts (2)

1-6: LGTM! Proper imports and module creation for mixed module systems.

The imports are correctly specified with the .js extension for ES modules. The use of createRequire is appropriate for importing CommonJS modules in an ES module context, ensuring compatibility with the native libvirt module.


323-329:

Details

✅ Verification successful

Verify flags handling in domainGetXMLDesc.

Ensure that the flags parameter is correctly passed to the native hypervisor. Some C bindings might have issues with optional parameters.

Run the following script to check how the native hypervisor handles flags:


🏁 Script executed:

#!/bin/bash
# Find all places where domainGetXMLDesc is called
rg "domainGetXMLDesc" -A 2 -B 2

Length of output: 1094


Flags parameter forwarding verified

After reviewing the usage in both the TypeScript (in lib/hypervisor.ts and lib/domain.ts) and native binding registrations (in src/hypervisor.cc), the investigation shows that the optional flags parameter is correctly passed down to the native hypervisor call as implemented. No discrepancies were found in its handling.

  • The code consistently forwards flags as-is to this.nativeHypervisor.domainGetXMLDesc.
  • All usages in the codebase (including the wrapper in lib/domain.ts) mirror this design.

If the native C binding cannot handle an undefined value (if that’s a potential concern), consider defaulting flags to a concrete value (e.g., 0). Otherwise, the current implementation is correct.

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 (7)
lib/hypervisor.ts (3)

12-13: Consider using a more explicit type for nativeHypervisor.
Currently, nativeHypervisor is declared as any. Defining a dedicated interface or type can increase type safety and readability.

-    private nativeHypervisor: any;
+    private nativeHypervisor: NativeHypervisor; // For example, define an interface "NativeHypervisor"

31-52: Log the original error as a cause for better debugging.
While wrapping errors is good practice, including the original error in the new LibvirtError (e.g., as a .cause property) can help preserve the stack trace.


62-68: Potential concurrency considerations for wrapMethod.
If multiple async calls occur in parallel, ensuring thread-safety or clarifying concurrency constraints in the documentation might be beneficial, particularly for stateful native operations.

__tests__/integration.test.ts (3)

71-94: Consider file operation resilience.
Using execSync to remove or inspect disk images is risky if run on locked or in-use files. Adding more robust error handling or fallback logic could prevent unexpected test failures.


96-160: Potential improvement: modularize domain cleanup.
Many steps are chained together, which is fine for manual debugging but can complicate maintenance. Extracting repeated cleanup steps into utility functions or a shared library might keep this file more concise.


212-333: Consider splitting this test into smaller scenarios.
The test covers multiple actions (create, define, start, shut down) in a single flow. Smaller, more focused tests can yield clearer failures and faster results.

Do you want help extracting each step (create, run, stop) into individual tests that share a common setup?

lib/types.ts (1)

131-149: Enhance LibvirtError with optional error cause chaining.
Modern JavaScript/TypeScript supports preserving the original cause in an error. Attaching the original cause can make debugging more effective.

 constructor(
   message: string,
   code: number,
   domain: number,
   level: number,
   str1?: string,
   str2?: string,
   str3?: string,
+  originalError?: any
 ) {
   super(message);
+  if (originalError) {
+    (this as any).cause = originalError;
+  }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 3f8ca21 and 215b769.

📒 Files selected for processing (3)
  • __tests__/integration.test.ts (1 hunks)
  • lib/hypervisor.ts (1 hunks)
  • lib/types.ts (6 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
__tests__/integration.test.ts (5)
lib/hypervisor.ts (1)
  • Hypervisor (12-349)
lib/types.ts (3)
  • Domain (129-129)
  • HypervisorOptions (4-6)
  • LibvirtError (131-149)
lib/domain.ts (1)
  • Domain (8-122)
lib/domain-desc.ts (1)
  • DomainDesc (103-150)
lib/domain-xml.ts (1)
  • domainDescToXml (300-412)
🔇 Additional comments (2)
lib/hypervisor.ts (1)

70-77: Implementation is clear and consistent.
The logic in connectOpen is straightforward and uses the standardized wrapMethod approach effectively.

__tests__/integration.test.ts (1)

11-48:

Details

❓ Verification inconclusive

Verify cross-platform compatibility.
The current architecture detection might fail on less common setups or unsupported environments. Consider skipping these tests or providing instructions if qemu-system-* is unavailable.


🏁 Script executed:

#!/bin/bash
# Attempt to locate qemu binaries for non-standard platforms
fd qemu-system- -x echo Found {}

Length of output: 36


Action Required: Manual Verification of QEMU Binaries on Non‑Standard Setups
The current architecture detection in getArchConfig() only covers typical macOS (darwin) and Linux environments, with hardcoded paths for qemu binaries. However, the supplied shell script (using fd) returned no output, indicating that on non‑standard platforms these binaries might not be detectable. Please manually verify the availability of these binaries on less common setups. Consider either:

  • Adding clearer fallback behavior (e.g., skipping integration tests if qemu-system-* is unavailable), or
  • Documenting pre‑test requirements/instructions for environments where the qemu binaries might not be installed.

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: 5

🧹 Nitpick comments (28)
lib/types.ts (2)

120-120: Add description for the NONE flag.

The other enum values have descriptive comments in the class-level JSDoc, but the NONE flag doesn't have an explanation of its purpose.

export enum DomainGetXMLDescFlags {
-    NONE = 0,
+    /** No special flags */
+    NONE = 0,
    SECURE = 1,
    INACTIVE = 2,
    UPDATE_CPU = 4,
    MIGRATABLE = 8
}

151-153: Enhance error message context for more error types.

You've improved the error message for 'Expected a number' errors, but similar improvements could be made for other common error types to help with debugging.

// Add more context to the error message
if (message === 'Expected a number.') {
    this.message = `Type error: Expected a number but received ${typeof str1 || 'undefined'}. This error typically occurs when calling libvirt methods that require numeric parameters.`;
+} else if (message === 'Expected a string.') {
+    this.message = `Type error: Expected a string but received ${typeof str1 || 'undefined'}. This error typically occurs when calling libvirt methods that require string parameters.`;
+} else if (message.includes('not found')) {
+    this.message = `Resource not found: ${message}. Please verify that the requested resource exists and you have proper permissions.`;
}
vitest.config.ts (1)

20-25: Consider more realistic coverage thresholds.

Setting all coverage thresholds to 100% is ambitious and may be difficult to maintain long-term, especially for edge cases and error handling branches. Consider slightly more forgiving thresholds (e.g., 90-95%) to balance thoroughness with practicality.

thresholds: {
-  branches: 100,
-  functions: 100,
-  lines: 100,
-  statements: 100
+  branches: 95,
+  functions: 100,
+  lines: 98,
+  statements: 98
}
__tests__/error.test.ts (1)

26-26: Replace delete operator with undefined assignment for better performance.

The static analysis tool correctly flags the use of the delete operator, which can impact performance. Assign undefined instead.

- delete errorWithoutStack.stack;
+ errorWithoutStack.stack = undefined;

- delete libvirtErrorNoStack.stack;
+ libvirtErrorNoStack.stack = undefined;

- delete errorWithAllPropsNoStack.stack;
+ errorWithAllPropsNoStack.stack = undefined;

- delete errorWithSomePropsNoStack.stack;
+ errorWithSomePropsNoStack.stack = undefined;

- delete errorWithNothingNoStack.stack;
+ errorWithNothingNoStack.stack = undefined;

Also applies to: 40-40, 112-112, 124-124, 131-131

🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

lib/error.ts (1)

55-61: Missing explicit return statement.

While the function will never reach line 60 because handleError always throws, TypeScript expects a return value of type T for this function.

export async function wrapMethod<T>(method: (...args: any[]) => Promise<T>, ...args: any[]): Promise<T> {
    try {
        return await method(...args);
    } catch (error) {
        handleError(error);
-    }
+        // This line is never reached as handleError always throws
+        return undefined as never;
+    }
}
lib/domain.spec.ts (1)

1-86: Consider adding more test cases for remaining Domain methods.

The current tests cover only a subset of the Domain class methods. For complete test coverage, consider adding tests for other methods like create, shutdown, destroy, and undefine.

lib/domain-xml.ts (2)

175-176: Use optional chaining for error prevention as suggested by static analysis.

Several places in the code are flagged by static analysis for missing optional chaining. Follow the pattern you've already applied in other sections.

Apply this diff to address static analysis warnings:

-if (disk.driver && disk.driver[0]) {
+if (disk.driver?.[0]) {

-if (disk.source && disk.source[0]) {
+if (disk.source?.[0]) {

-if (disk.target && disk.target[0]) {
+if (disk.target?.[0]) {

-if (iface.source && iface.source[0]) {
+if (iface.source?.[0]) {

-if (iface.mac && iface.mac[0]) {
+if (iface.mac?.[0]) {

-if (iface.model && iface.model[0]) {
+if (iface.model?.[0]) {

Also applies to: 186-186, 193-193, 246-246, 253-253, 260-260

🧰 Tools
🪛 Biome (1.9.4)

[error] 175-175: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


369-369: Fix switch clause variable declaration issue.

Static analysis detected an issue with the declaration of emulatorDesc in a switch clause, which can potentially be accessed by other clauses.

case 'emulator':
-    const emulatorDesc = deviceDesc.emulator;
-    if (emulatorDesc.value) {
-        domain.devices.emulator.push({
-            _: emulatorDesc.value
-        });
-    }
+    {
+        const emulatorDesc = deviceDesc.emulator;
+        if (emulatorDesc.value) {
+            domain.devices.emulator.push({
+                _: emulatorDesc.value
+            });
+        }
+    }
    break;
🧰 Tools
🪛 Biome (1.9.4)

[error] 369-369: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

__tests__/domain-listing.test.ts (1)

9-11: Improve type safety by using specific types

The connection and archConfig variables are typed as any, which reduces type safety. Consider using more specific types for better IDE support and compile-time checks.

-    let connection: any;
+    let connection: import('../lib').Connect;
-    let archConfig: any;
+    let archConfig: { arch: string; machine: string; emulator: string; firmware?: { vars: string } };
__tests__/domain-cleanup.test.ts (5)

9-11: Improve type safety by using specific types

The connection and archConfig variables are typed as any, which reduces type safety. Consider using more specific types for better IDE support and compile-time checks.

-    let connection: any;
+    let connection: import('../lib').Connect;
-    let archConfig: any;
+    let archConfig: { arch: string; machine: string; emulator: string; firmware?: { vars: string } };

39-60: Reduce code duplication by extracting common domain configuration

The same domain configuration is repeated in both test cases. Consider extracting it to a helper function or a constant to reduce duplication.

+    const createMinimalDomainDesc = (): DomainDesc => ({
+        type: 'qemu',
+        name: TEST_VM_NAME,
+        memory: { value: 512 * 1024 },
+        vcpu: { value: 1 },
+        os: {
+            type: { 
+                arch: archConfig.arch,
+                machine: archConfig.machine,
+                value: 'hvm'
+            },
+            boot: { dev: 'hd' }
+        },
+        devices: [
+            {
+                type: 'emulator',
+                emulator: {
+                    value: archConfig.emulator
+                }
+            }
+        ]
+    });

     it('should allow undefining a domain through the domain object', async () => {
         // Create a minimal VM configuration
-        const domainDesc: DomainDesc = {
-            type: 'qemu',
-            name: TEST_VM_NAME,
-            memory: { value: 512 * 1024 },
-            vcpu: { value: 1 },
-            os: {
-                type: { 
-                    arch: archConfig.arch,
-                    machine: archConfig.machine,
-                    value: 'hvm'
-                },
-                boot: { dev: 'hd' }
-            },
-            devices: [
-                {
-                    type: 'emulator',
-                    emulator: {
-                        value: archConfig.emulator
-                    }
-                }
-            ]
-        };
+        const domainDesc = createMinimalDomainDesc();

72-74: Remove unnecessary null check

The code has already confirmed that domain is not null on line 65 with the expectation check. The null check here is redundant.

-        if (domain) {
-            await domain.undefine();
-        }
+        await domain.undefine();

83-104: Reuse domain configuration to reduce duplication

Use the extracted helper function for creating the domain description.

-        const domainDesc: DomainDesc = {
-            type: 'qemu',
-            name: TEST_VM_NAME,
-            memory: { value: 512 * 1024 },
-            vcpu: { value: 1 },
-            os: {
-                type: { 
-                    arch: archConfig.arch,
-                    machine: archConfig.machine,
-                    value: 'hvm'
-                },
-                boot: { dev: 'hd' }
-            },
-            devices: [
-                {
-                    type: 'emulator',
-                    emulator: {
-                        value: archConfig.emulator
-                    }
-                }
-            ]
-        };
+        const domainDesc = createMinimalDomainDesc();

116-118: Remove unnecessary null check

The code has already confirmed that domain is not null on line 109 with the expectation check. The null check here is redundant.

-        if (domain) {
-            await connection.domainUndefine(domain);
-        }
+        await connection.domainUndefine(domain);
__tests__/domain-lifecycle.test.ts (4)

9-11: Improve type safety by using specific types

The connection and archConfig variables are typed as any, which reduces type safety. Consider using more specific types for better IDE support and compile-time checks.

-    let connection: any;
+    let connection: import('../lib').Connect;
-    let archConfig: any;
+    let archConfig: { arch: string; machine: string; emulator: string; firmware?: { vars: string } };

93-93: Remove console.log from production code

Console logging statements should be removed before submitting the code. Consider using a test logger if debugging information is needed.

-        console.log('Generated XML:', xml);

This applies to all console.log statements in this file.


40-41: Use asynchronous file operations

Using execSync can block the event loop. Consider using the asynchronous version of file operations.

-            execSync(`cp "${archConfig.firmware.vars}" "/tmp/test-vm.nvram"`);
+            await fs.promises.copyFile(archConfig.firmware.vars, "/tmp/test-vm.nvram");

You'll need to import the fs module:

import * as fs from 'fs';

96-96: Use asynchronous file operations

Using execSync can block the event loop. Consider using the asynchronous version of file operations.

-        execSync(`qemu-img create -f qcow2 ${DISK_IMAGE} 1G`);
+        await util.promisify(exec)(`qemu-img create -f qcow2 ${DISK_IMAGE} 1G`);

You'll need to import the util module and change the import for child_process:

-import { execSync } from 'child_process';
+import { exec } from 'child_process';
+import * as util from 'util';
.github/workflows/docker-integration.yml (3)

54-54: Use more specific Docker image tag

The current tag libvirt-test-${{ matrix.arch }} might conflict with other images. Consider adding the commit SHA or another unique identifier to the tag.

-            -t libvirt-test-${{ matrix.arch }} \
+            -t libvirt-test-${{ matrix.arch }}-${{ github.sha }} \

Also update the reference to this tag on line 65:

-            libvirt-test-${{ matrix.arch }}
+            libvirt-test-${{ matrix.arch }}-${{ github.sha }}

49-49: Fix linting issues: Remove trailing whitespace

There are trailing spaces on this line that should be removed to fix linting issues.

-          
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 49-49: trailing spaces

(trailing-spaces)


73-73: Fix linting issues: Add newline at end of file and remove trailing whitespace

Add a newline at the end of the file and remove trailing spaces to fix linting issues.

-          retention-days: 7 
+          retention-days: 7
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 73-73: no new line character at the end of file

(new-line-at-end-of-file)


[error] 73-73: trailing spaces

(trailing-spaces)

Dockerfile (1)

53-54: Use a more robust setup for the daemon start

The current command uses a fixed sleep duration (2 seconds) which might not be sufficient for the daemon to fully initialize on all systems, potentially causing race conditions in tests.

Consider using a healthcheck approach instead:

-CMD ["/bin/sh", "-c", "/usr/sbin/libvirtd --daemon && sleep 2 && npm test"]
+CMD ["/bin/sh", "-c", "/usr/sbin/libvirtd --daemon && while ! virsh -c qemu:///session list > /dev/null 2>&1; do sleep 0.5; done && npm test"]
lib/domain-builder.spec.ts (1)

95-107: Consider testing additional template properties

While you test the basic template functionality, consider adding assertions for more complex nested properties to ensure they are properly preserved.

You could enhance the template test with more complex structures:

const template: DomainDesc = {
    name: 'template-vm',
    memory: { unit: 'KiB', value: 1024 * 1024 },
    vcpu: { placement: 'static', value: 1 },
+   devices: [
+       {
+           type: 'disk',
+           disk: {
+               type: 'file',
+               device: 'disk',
+               source: { file: '/path/to/disk.img' },
+               target: { dev: 'vda', bus: 'virtio' }
+           }
+       }
+   ]
};
__tests__/hypervisor.test.ts (2)

150-151: Use unique temporary paths for test files

The hardcoded path for the save file (/tmp/domain-save-test) could cause issues if tests run in parallel or if previous test runs failed to clean up.

Consider generating a unique filename:

-const saveFile = '/tmp/domain-save-test';
+const saveFile = `/tmp/domain-save-test-${Date.now()}-${Math.floor(Math.random() * 10000)}`;

47-53: Improve error handling for KVM check

The current approach just logs a message if KVM is not available, but doesn't indicate this in the test output.

Consider this approach that makes the skip more explicit:

try {
    const maxVcpusKvm = await connection.connectGetMaxVcpus('kvm');
    expect(maxVcpusKvm).toBeGreaterThan(0);
} catch (error) {
-    // Some systems might not support KVM, so we'll just log this
-    console.log('KVM not available on this system');
+    // Some systems might not support KVM
+    console.log('Skipping KVM test: not available on this system');
+    expect((error as Error).message).toContain('Error'); // Verify it's an expected error
}
__tests__/helpers.ts (3)

9-40: Architecture detection can be simplified.

The architecture detection logic has duplicated code paths for Darwin and other platforms that could be consolidated.

export function getArchConfig(): { arch: string; machine: string; firmware?: { code: string; vars: string }; emulator: string } {
-    if (process.platform === 'darwin') {
-        if (process.arch === 'arm64') {
-            return {
-                arch: 'aarch64',
-                machine: 'virt',
-                emulator: '/usr/bin/qemu-system-aarch64'
-            };
-        } else {
-            return {
-                arch: 'x86_64',
-                machine: 'q35',
-                emulator: '/usr/bin/qemu-system-x86_64'
-            };
-        }
-    } else {
-        if (process.arch === 'arm64') {
-            return {
-                arch: 'aarch64',
-                machine: 'virt',
-                emulator: '/usr/bin/qemu-system-aarch64'
-            };
-        } else {
-            return {
-                arch: 'x86_64',
-                machine: 'q35',
-                emulator: '/usr/bin/qemu-system-x86_64'
-            };
-        }
-    }
+    if (process.arch === 'arm64') {
+        return {
+            arch: 'aarch64',
+            machine: 'virt',
+            emulator: '/usr/bin/qemu-system-aarch64'
+        };
+    } else {
+        return {
+            arch: 'x86_64', 
+            machine: 'q35',
+            emulator: '/usr/bin/qemu-system-x86_64'
+        };
+    }
}

63-86: Consider parameterizing hardcoded paths in disk cleanup.

The current implementation uses hardcoded paths which may limit flexibility and portability.

-export const cleanupDiskImage = () => {
+export const cleanupDiskImage = (diskImagePath = DISK_IMAGE, nvramPattern = '/tmp/test-vm.nvram*') => {
    try {
        // Clean up disk image
-        if (existsSync(DISK_IMAGE)) {
+        if (existsSync(diskImagePath)) {
            // Try to remove any locks first
            try {
-                execSync(`qemu-img info ${DISK_IMAGE} --force-share`);
+                execSync(`qemu-img info ${diskImagePath} --force-share`);
            } catch (error) {
                // Ignore errors from force-share
            }
            // Remove the disk image
-            execSync(`rm -f ${DISK_IMAGE}`);
+            execSync(`rm -f ${diskImagePath}`);
        }
        // Clean up NVRAM files
        try {
-            execSync('rm -f /tmp/test-vm.nvram*');
+            execSync(`rm -f ${nvramPattern}`);
        } catch (error) {
            // Ignore errors from NVRAM cleanup
        }
    } catch (error) {
        console.error('Error cleaning up files:', error);
    }
};

88-152: Extract wait logic and use consistent error logging.

The domain cleanup function includes repeated timeout logic that could be extracted, and uses inconsistent error logging approaches.

Create a sleep helper function and use consistent error handling:

+// Helper function for waiting
+const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

 export const cleanupDomain = async (connection: Hypervisor) => {
     try {
         console.log('Starting domain cleanup...');
         
         // Check both defined and active domains
         const definedDomains = await connection.connectListDefinedDomains();
         const activeDomainIds = await connection.connectListDomains();
         console.log('Defined domains:', definedDomains);
         console.log('Active domain IDs:', activeDomainIds);

         // Check if domain exists in either list
         if (definedDomains.includes(TEST_VM_NAME) || activeDomainIds.length > 0) {
             console.log(`Found existing domain ${TEST_VM_NAME}, attempting cleanup...`);
             try {
                 const existingDomain = await connection.domainLookupByName(TEST_VM_NAME);
                 if (existingDomain) {
                     try {
                         const info = await existingDomain.getInfo();
                         console.log('Domain state:', info.state);
                         if (info.state === DomainState.RUNNING) {
                             // Try graceful shutdown first
                             try {
                                 console.log('Attempting graceful shutdown...');
                                 await existingDomain.shutdown();
-                                await new Promise(resolve => setTimeout(resolve, 2000));
+                                await sleep(2000);
                             } catch (error) {
-                                console.log('Graceful shutdown failed:', error instanceof Error ? error.message : error);
+                                console.error('Graceful shutdown failed:', error instanceof Error ? error.message : error);
                             }
                             // Force shutdown if still running
                             try {
                                 console.log('Attempting force shutdown...');
                                 await existingDomain.destroy();
-                                await new Promise(resolve => setTimeout(resolve, 2000));
+                                await sleep(2000);
                             } catch (error) {
-                                console.log('Force shutdown failed:', error instanceof Error ? error.message : error);
+                                console.error('Force shutdown failed:', error instanceof Error ? error.message : error);
                             }
                         }
                     } catch (error) {
-                        console.log('Error getting domain info:', error instanceof Error ? error.message : error);
+                        console.error('Error getting domain info:', error instanceof Error ? error.message : error);
                     }
                 }
             } catch (error) {
-                console.log('Error looking up domain:', error instanceof Error ? error.message : error);
+                console.error('Error looking up domain:', error instanceof Error ? error.message : error);
             }

             // Now try to undefine the domain
             try {
                 console.log('Attempting to undefine domain...');
                 const domain = await connection.domainLookupByName(TEST_VM_NAME);
                 if (domain) {
                     await connection.domainUndefine(domain);
-                    await new Promise(resolve => setTimeout(resolve, 2000));
+                    await sleep(2000);
                     console.log('Domain undefined successfully');
                 }
             } catch (error) {
-                console.log('Error during undefine:', error instanceof Error ? error.message : error);
+                console.error('Error during undefine:', error instanceof Error ? error.message : error);
             }
         } else {
             console.log('No existing domain found to clean up');
         }
     } catch (error) {
         console.error('Error during domain cleanup:', error instanceof Error ? error.message : error);
     }
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 215b769 and add8eb3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • .github/workflows/docker-integration.yml (1 hunks)
  • .gitignore (1 hunks)
  • Dockerfile (1 hunks)
  • __tests__/domain-cleanup.test.ts (1 hunks)
  • __tests__/domain-lifecycle.test.ts (1 hunks)
  • __tests__/domain-listing.test.ts (1 hunks)
  • __tests__/error.test.ts (1 hunks)
  • __tests__/helpers.ts (1 hunks)
  • __tests__/hypervisor.test.ts (1 hunks)
  • lib/domain-builder.spec.ts (1 hunks)
  • lib/domain-xml.spec.ts (9 hunks)
  • lib/domain-xml.ts (7 hunks)
  • lib/domain.spec.ts (1 hunks)
  • lib/error.ts (1 hunks)
  • lib/hypervisor.ts (1 hunks)
  • lib/types.spec.ts (1 hunks)
  • lib/types.ts (6 hunks)
  • package.json (4 hunks)
  • vitest.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🧬 Code Definitions (5)
lib/types.spec.ts (1)
lib/types.ts (1)
  • LibvirtError (132-159)
lib/domain.spec.ts (2)
lib/types.ts (1)
  • Domain (130-130)
lib/hypervisor.ts (6)
  • Hypervisor (13-316)
  • domainSave (151-157)
  • domainGetXMLDesc (266-272)
  • domainGetID (226-231)
  • domainGetName (239-244)
  • domainGetUUIDString (252-257)
lib/hypervisor.ts (8)
lib/index.ts (2)
  • Hypervisor (5-5)
  • Domain (6-6)
src/hypervisor.cc (1)
  • Hypervisor (57-78)
src/hypervisor.h (1)
  • Hypervisor (48-48)
lib/error.ts (1)
  • wrapMethod (55-61)
lib/domain.ts (1)
  • Domain (8-122)
lib/types.ts (1)
  • Domain (130-130)
src/domain.h (2)
  • Domain (22-22)
  • Domain (23-23)
src/hypervisor-domain.cc (1)
  • id (199-211)
lib/error.ts (1)
lib/types.ts (1)
  • LibvirtError (132-159)
lib/types.ts (3)
src/domain.h (2)
  • Domain (22-22)
  • Domain (23-23)
lib/index.ts (1)
  • Domain (6-6)
lib/domain.ts (1)
  • Domain (8-122)
🪛 Biome (1.9.4)
lib/domain-xml.ts

[error] 175-175: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 186-186: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 193-193: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 246-246: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 253-253: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 260-260: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 369-369: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

__tests__/error.test.ts

[error] 26-26: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 40-40: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 112-112: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 124-124: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 131-131: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🪛 YAMLlint (1.35.1)
.github/workflows/docker-integration.yml

[error] 49-49: trailing spaces

(trailing-spaces)


[error] 73-73: no new line character at the end of file

(new-line-at-end-of-file)


[error] 73-73: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Docker Integration Tests (arm64)
  • GitHub Check: Docker Integration Tests (amd64)
🔇 Additional comments (57)
lib/types.ts (2)

130-130: Reconsider using any for the Domain type.

Using any bypasses TypeScript's type safety, which can lead to runtime errors. This was previously flagged in an earlier review. Consider creating a proper interface that defines the expected shape of Domain objects.

-export type Domain = any;
+export interface Domain {
+   // Define known properties here
+   // This could be populated based on the actual domain structure
+}

132-159: LGTM! Well-designed error class.

The LibvirtError class is well-structured with appropriate properties and methods. The additional context for error messages and the formatted toString() method will be helpful for debugging.

lib/types.spec.ts (1)

1-20: LGTM! Comprehensive test coverage for LibvirtError.

The tests thoroughly validate the key functionality of the LibvirtError class:

  • Error message enhancement for numeric type errors
  • Correct formatting of error information in the toString method
  • Proper handling of undefined values
vitest.config.ts (1)

1-36: LGTM! Well-configured Vitest setup.

The configuration includes appropriate settings for the test environment, file patterns, coverage reporting, and timeouts. Using the 'v8' coverage provider is a good choice for accurate coverage reporting.

__tests__/error.test.ts (1)

5-161: LGTM! Comprehensive error handling test cases.

The tests cover an impressive range of error scenarios, which will help ensure robust error handling throughout the application. Testing various error types, object structures, and edge cases provides excellent coverage of the error handling logic.

🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 40-40: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 112-112: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 124-124: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 131-131: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

lib/error.ts (2)

1-7: Good documentation for error handling function.

The JSDoc comment clearly explains the purpose and behavior of the handleError function. It's valuable to explicitly document the throw behavior as this helps users understand the control flow.


8-46: Comprehensive error handling with well-structured conversion.

The handleError function effectively handles different error types (Error instances, strings, and other objects) and consistently converts them to LibvirtError instances with appropriate fallbacks. The preservation of stack traces is particularly valuable for debugging.

lib/domain.spec.ts (5)

1-5: Appropriate test framework setup.

Good choice of testing framework (Vitest) and proper imports of the components to be tested.


6-46: Well-structured test setup with comprehensive mocking.

The test setup properly mocks all necessary Hypervisor methods and initializes the Domain instance with mock dependencies. This approach isolates the Domain class for focused testing.


48-54: Good test case for save method.

The test properly verifies that the Domain.save method correctly delegates to the hypervisor's domainSave method with the right parameters.


56-69: Comprehensive testing of getXMLDesc with and without flags.

Good approach testing both the default behavior (no flags) and with specific flags. This ensures the method works correctly in different scenarios.


71-85: Complete test coverage for ID and UUID retrieval.

Tests for getID and getUUIDString are well-structured, verifying both the return values and correct delegation to the hypervisor methods.

lib/domain-xml.ts (4)

55-82: Support for loader property with array handling.

Good implementation of the loader property serialization with support for both array and single-object inputs. The code correctly handles all optional properties.


89-124: Improved safety with optional chaining for property access.

Using optional chaining (?.) for accessing properties prevents potential null/undefined errors. The loader property deserialization is properly implemented.


362-363: Added support for ACPI devices.

The addition of the 'acpi' array to the devices object appropriately extends the serialization capabilities.


401-403: Implemented ACPI device type handling.

The new case to handle 'acpi' device type follows the established pattern for device handling.

lib/hypervisor.ts (7)

1-24: Well-structured class with appropriate imports and initialization.

The Hypervisor class is well-designed with clear imports and a constructor that properly initializes the native hypervisor connection. Good use of JSDoc comments to document the class and constructor.


30-40: Consistent error handling with wrapMethod.

The implementation properly uses the wrapMethod utility for standardized error handling, which is an improvement over duplicating try/catch blocks in each method.


49-55: Comprehensive domain listing with proper type handling.

The connectListAllDomains method correctly maps native domain objects to Domain instances and provides sensible default flags.


81-101: Good domain creation methods with proper domain wrapping.

Both domainCreateXML and domainDefineXML are well-implemented, properly wrapping the native domains in Domain instances for easier use.


151-205: Comprehensive domain management methods with consistent patterns.

The domain management methods (save, create, shutdown, destroy, undefine) all follow a consistent pattern and are well-documented with JSDoc comments.


213-272: Thorough domain information retrieval methods.

The methods for retrieving domain information (getInfo, getID, getName, getUUIDString, getXMLDesc) are well-implemented and follow a consistent pattern.


280-315: Good hypervisor and node information methods.

The methods for retrieving hypervisor and node information, along with the domain restore method, complete the class with a comprehensive API.

Dockerfile (3)

21-26: LGTM: Good security practice using non-root user

Creating a non-root user for running libvirt is a good security practice. The setup correctly adds the user to the necessary groups and sets appropriate permissions.


39-42: Recheck security implications of auth_unix_rw = "none".

This setting removes authentication for the read-write socket, which might be acceptable in a restricted container environment but could be a security concern if containers share the same host environment.


2-2:

Details

✅ Verification successful

Downgraded Node.js version from 22 to 20

The base image has been downgraded from Node.js 22 to 20. While this might be intentional for compatibility reasons, ensure this aligns with your application requirements.


🏁 Script executed:

#!/bin/bash
# Check if there are any dependencies or code that requires Node.js 20 specifically
grep -r "engines" --include="package.json" .

Length of output: 13571


Node.js Version Downgrade Verified

The Dockerfile now uses FROM node:20-slim, and a scan of the engines fields across package.json files (including those in dependencies) shows that none explicitly require Node.js 22. Most dependencies indicate compatibility with older versions (e.g., >=10), which suggests that the downgrade is safe.

Please ensure that the application's primary package.json (if an engines field is defined) also aligns with targeting Node.js 20. Otherwise, no further changes are required.

lib/domain-builder.spec.ts (1)

1-126: Excellent test coverage for the DomainBuilder class

The test suite is comprehensive and well-structured, covering all the key functionality of the DomainBuilder class including creating domains, setting properties, and managing devices. The tests properly validate both the positive cases and removal operations.

package.json (3)

29-31: LGTM: Successfully migrated from Mocha to Vitest

The test framework has been updated from Mocha to Vitest with appropriate scripts for running tests, generating coverage reports, and accessing the UI. This is a good modernization of the testing infrastructure.


102-103: LGTM: Clear system requirements specification

The system requirements have been updated from text descriptions to specific version numbers, which makes it much clearer what versions of libvirt and QEMU are required. This is more precise than the previous descriptions.


75-77:

Details

✅ Verification successful

Verify Vitest compatibility with project requirements

Ensure that the newly added Vitest dependencies and their versions are compatible with your other tools and CI pipeline.

Also applies to: 87-88


🏁 Script executed:

#!/bin/bash
# Check if Vitest is compatible with the current Node.js version and TypeScript version
echo "Node.js version:"
node -v
echo "TypeScript version:"
grep "typescript" package.json
echo "Vitest version:"
grep "vitest" package.json

Length of output: 566


Vitest Dependency Versions are Consistent and Compatible

The Node.js (v22.9.0), TypeScript (^5.7.3), and Vitest (^1.3.1) versions in the package.json have been verified and are aligned. There are no version conflicts, and the test scripts reflect the intended usage of Vitest. Please ensure that the CI pipeline is updated to run the Vitest commands as configured.

  • Verify package.json lines 75–77 (Vitest and its plugins) and lines 87–88 (test scripts).
  • Confirm that your CI environment supports Node.js v22.9.0 and has the necessary settings for Vitest execution.
__tests__/hypervisor.test.ts (2)

13-35: LGTM: Proper test setup and teardown

The test suite includes well-structured setup and teardown procedures to ensure resources are properly initialized and cleaned up, even if tests fail. The timeout values are appropriate for these operations.


250-260: LGTM: Thorough error handling tests

The error handling tests are well-designed to verify that the system properly rejects invalid inputs and throws the expected error types. This is essential for robust API design.

lib/domain-xml.spec.ts (21)

13-13: Good addition of Vitest for test framework.

The import of describe and it from Vitest demonstrates a migration to or addition of Vitest alongside Chai, which is a positive modernization of the testing infrastructure.


51-68: Good handling of missing type value edge case.

This test properly verifies that the XML serialization gracefully handles the case when a domain OS type has attributes but no value.


70-84: Proper validation of edge case with missing boot dev attribute.

This test ensures the serialization correctly handles empty boot elements, which is essential for robust XML generation.


86-100: Good coverage for empty loader fields serialization.

This test verifies that empty loader configurations are serialized correctly, improving the robustness of the serialization process.


102-125: Well-implemented test for loader array serialization.

This test thoroughly validates that arrays of loaders with various missing fields are serialized correctly, ensuring compatibility with different configurations.


146-185: Comprehensive testing of OS XML serialization and deserialization.

These tests thoroughly validate both full and minimal OS configurations in both serialization and deserialization paths, ensuring robustness and compatibility across various use cases.

Also applies to: 187-201, 203-241, 243-256


258-272: Excellent coverage of OS XML edge cases.

These tests thoroughly verify handling of missing optional fields and empty configurations during serialization and deserialization, which is crucial for handling real-world XML variations.

Also applies to: 274-287, 289-305, 307-321, 323-343


369-395: Good test for disk serialization with missing fields.

This test ensures that disk serialization works correctly even when type and device fields are missing, supporting backward compatibility and resilience.


419-598: Comprehensive validation of disk XML handling.

These tests thoroughly cover optional field handling, serialization and deserialization of full and partial disk configurations, ensuring robust XML handling for all disk scenarios.


601-647: Thorough testing of empty disk object cases.

These tests verify that disk configurations with empty object properties are handled gracefully during both serialization and deserialization.


673-697: Good validation of interfaces without type field.

This test ensures that network interfaces without a specified type can still be properly serialized, which is important for backward compatibility and handling incomplete configurations.


722-866: Comprehensive testing of interface XML edge cases.

These tests thoroughly verify the handling of optional fields, full configurations, partial configurations, and empty objects in interface serialization and deserialization.


906-982: Complete coverage for graphics XML variations.

These tests validate the serialization and deserialization of graphics configurations with various combinations of fields and empty properties, ensuring robust handling of VNC and other display options.


1182-1243: Good tests for memory and CPU value handling.

These tests ensure proper parsing of string values and attributes for memory and vcpu elements, which is essential for correctly interpreting VM configurations.


1245-1254: Important validation of error handling for invalid XML.

This test ensures that the parsing function properly rejects invalid XML inputs with appropriate error messages, improving the robustness of the API.


1256-1321: Good tests for loader configurations in domain XML.

These tests verify that both single and multiple loader configurations are correctly serialized and deserialized, which is important for UEFI boot support.


1323-1393: Excellent round-trip conversion test.

This test validates that a domain description can be converted to XML and back to a domain description without losing information, which is crucial for the overall reliability of the XML handling.


1395-1449: Comprehensive tests for attribute handling.

These tests verify the correct handling of different attribute formats and optional attributes for memory and CPU configurations.


1451-1476: Good error handling and edge case validation.

These tests ensure that invalid XML is rejected and minimal domain configurations are handled correctly.


1478-1503: Good handling of edge cases for device types.

These tests verify that unknown device types are handled gracefully and known types like ACPI are serialized correctly.


1505-1519: Proper domain ID handling.

These tests ensure that domain IDs are correctly serialized and deserialized, which is important for domain identification.

__tests__/helpers.ts (4)

1-8: Well-structured test helper imports and constants.

Good organization with clear import statements and constants for test VM name and disk image path.


42-61: Good QEMU verification function.

This function properly verifies the existence of required QEMU components before tests run, which prevents confusing test failures due to missing prerequisites.


154-164: Good disk image creation function.

This function creates a test disk image with proper error handling and logging.


166-187: Well-structured test environment setup.

This function provides a clean, sequential setup process for test environments, ensuring all prerequisites are in place before tests run.

throw error;
} finally {
// Clear the domain reference before cleanup
domain = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider maintaining domain reference for cleanup

Setting domain = null in the finally block might interfere with the cleanup in the afterAll hook. Consider removing this line or setting a flag to indicate that cleanup has already been performed.


🏁 Script executed:

#!/bin/bash
# Check if the domain reference is needed for cleanup in afterAll
grep -B 5 -A 15 "afterAll" __tests__/domain-lifecycle.test.ts

Length of output: 1255


Action Required: Preserve Domain Reference Until Global Cleanup

Based on the inspection of the tests/domain-lifecycle.test.ts file, the afterAll hook checks for the existence of the domain reference (via an if (domain) condition) to perform its cleanup routine before resetting it to null. Setting domain = null in an earlier finally block (as shown on line 154) risks clearing this reference too soon, which would prevent the cleanup code in afterAll from executing its intended actions.

Please Address the Following:

  • Either remove the premature domain = null; assignment from the finally block so that afterAll can correctly detect and clean up the domain.
  • Or replace it with logic (such as a flag) that indicates cleanup has already been performed, ensuring that afterAll behaves accordingly.

Comment on lines 37 to 38
sudo chmod -R 777 /var/run/libvirt
sudo chmod -R 777 /var/lib/libvirt
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use more restrictive permissions for libvirt directories

Setting directories to 777 permissions is overly permissive and could be a security concern. Consider using more restrictive permissions that still allow the necessary access.

-          sudo chmod -R 777 /var/run/libvirt
-          sudo chmod -R 777 /var/lib/libvirt
+          sudo chmod -R 755 /var/run/libvirt
+          sudo chmod -R 755 /var/lib/libvirt
+          sudo chown -R $(id -u):$(id -g) /var/run/libvirt
+          sudo chown -R $(id -u):$(id -g) /var/lib/libvirt
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sudo chmod -R 777 /var/run/libvirt
sudo chmod -R 777 /var/lib/libvirt
sudo chmod -R 755 /var/run/libvirt
sudo chmod -R 755 /var/lib/libvirt
sudo chown -R $(id -u):$(id -g) /var/run/libvirt
sudo chown -R $(id -u):$(id -g) /var/lib/libvirt

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 (3)
.github/workflows/main.yml (3)

42-44: Updated Cache APT Packages:
The caching step now includes qemu-system and qemu-user-static along with libvirt-dev. Please verify that these additional packages are indeed required for your workflow and are available on the runner environment.


85-91: Creating libvirt Directories with Broad Permissions:
The workflow creates required libvirt directories and applies 777 permissions to ensure unrestricted access during CI runs. While this is acceptable for a controlled testing environment, consider tightening the permissions if this configuration is ever applied outside of CI to minimize potential security risks.


96-96: Remove Trailing Whitespace:
Static analysis indicates trailing spaces on this line. Removing them will help maintain clean YAML formatting.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 96-96: trailing spaces

(trailing-spaces)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between add8eb3 and 3f865a3.

📒 Files selected for processing (1)
  • .github/workflows/main.yml (2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
.github/workflows/main.yml

[error] 96-96: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (5)
.github/workflows/main.yml (5)

75-79: Added Docker Buildx Setup:
The new step for setting up Docker Buildx is correctly implemented. This configuration is essential for building multi-architecture images, and the install: true flag ensures the Buildx installation is enforced.


80-84: Configured QEMU Setup:
The integration of QEMU to support the linux/amd64 and linux/arm64 platforms is a solid addition. Ensure these are the intended target architectures and that any dependency on QEMU in your integration tests is well-documented.


92-117: Implementation of Docker Integration Tests:
The integration tests are comprehensive—they build Docker images for both amd64 and arm64 platforms and run container tests with necessary privileges. Please re-confirm that using --privileged mode and the specified volume bindings is strictly needed, as they grant elevated access. Additionally, these tests assume that all necessary libvirt services will be correctly mounted inside the container.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 96-96: trailing spaces

(trailing-spaces)


118-124: Upload Test Artifacts Step:
The step to upload test artifacts is clearly configured with a 7-day retention policy. This will ensure that any logs or output from the integration tests are preserved for debugging purposes if needed.


126-132: Upload Coverage Reports Step:
This step uploads the coverage reports as artifacts and uses a consistent retention period of 7 days. Verify that the coverage directory is correctly generated by your tests so that the expected files are available for upload.

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 (10)
__tests__/helpers.ts (4)

9-56: Architecture detection implementation can be simplified.

The function correctly determines architecture-specific configurations for QEMU, but the conditional branches for macOS and other platforms contain identical code paths for each architecture.

export function getArchConfig(): { arch: string; machine: string; firmware?: { code: string; vars: string }; emulator: string } {
    // Check for QEMU in Homebrew path on macOS
    const homebrewQemuPath = process.platform === 'darwin' ? '/opt/homebrew/bin' : null;
    const systemQemuPath = '/usr/bin';
    
    // Function to find QEMU binary
    const findQemuBinary = (arch: string): string => {
        const binaryName = `qemu-system-${arch}`;
        if (homebrewQemuPath && existsSync(`${homebrewQemuPath}/${binaryName}`)) {
            return `${homebrewQemuPath}/${binaryName}`;
        }
        if (existsSync(`${systemQemuPath}/${binaryName}`)) {
            return `${systemQemuPath}/${binaryName}`;
        }
        throw new Error(`QEMU binary ${binaryName} not found in ${homebrewQemuPath} or ${systemQemuPath}`);
    };

-    if (process.platform === 'darwin') {
-        if (process.arch === 'arm64') {
-            return {
-                arch: 'aarch64',
-                machine: 'virt',
-                emulator: findQemuBinary('aarch64')
-            };
-        } else {
-            return {
-                arch: 'x86_64',
-                machine: 'q35',
-                emulator: findQemuBinary('x86_64')
-            };
-        }
-    } else {
-        if (process.arch === 'arm64') {
-            return {
-                arch: 'aarch64',
-                machine: 'virt',
-                emulator: findQemuBinary('aarch64')
-            };
-        } else {
-            return {
-                arch: 'x86_64',
-                machine: 'q35',
-                emulator: findQemuBinary('x86_64')
-            };
-        }
-    }
+    // The configuration is the same regardless of platform, only depends on architecture
+    if (process.arch === 'arm64') {
+        return {
+            arch: 'aarch64',
+            machine: 'virt',
+            emulator: findQemuBinary('aarch64')
+        };
+    } else {
+        return {
+            arch: 'x86_64',
+            machine: 'q35',
+            emulator: findQemuBinary('x86_64')
+        };
+    }
}

89-111: Disk cleanup could use safer string interpolation.

The function effectively cleans up disk images and NVRAM files, but uses direct string interpolation in shell commands which could be a security risk if the constants were user-provided.

Consider using path sanitization or escaping for the shell commands, even though in this case the paths are constants defined in the file.


113-177: Domain cleanup logic is thorough but could be simplified.

The domain cleanup function has comprehensive error handling but contains some redundant checks and could be streamlined.

  1. On line 125, the condition activeDomainIds.length > 0 doesn't guarantee that one of those domains is the TEST_VM_NAME.
  2. Lines 129-130 check if existingDomain exists, but it will always exist if the previous line didn't throw.
  3. On line 162-163, you repeat the domain lookup that was already done earlier.

Consider refactoring the flow to reduce redundant checks and domain lookups.


1-212: Consider adding a cleanup function for the entire test environment.

The file provides functions for setting up the test environment, but is missing a comprehensive cleanup function that could be used in test teardown.

Consider adding a teardownTestEnv function that:

  1. Cleans up the domain
  2. Closes the hypervisor connection
  3. Cleans up the disk image

This would complement the setupTestEnv function and ensure proper resource cleanup after tests.

.github/workflows/main.yml (4)

85-91: Libvirt Directory Permissions
The workflow creates and adjusts permissions for libvirt directories using chmod -R 777. While acceptable for a controlled CI environment, please verify that such permissive settings are not propagated to production. Consider whether more restrictive permissions might be feasible.


120-127: Quoting Shell Substitution in Docker Run
The docker run command maps the local test artifacts directory using a command substitution ($(pwd)). To prevent potential word-splitting issues (especially if the path contains spaces), it’s recommended to quote the substitution. For example:

-              -v $(pwd)/test-artifacts:/app/test-artifacts \
+              -v "$(pwd)/test-artifacts":/app/test-artifacts \

96-96: Remove Trailing Spaces
A trailing space was detected on this line. Please remove any extraneous white space to keep the YAML clean.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 96-96: trailing spaces

(trailing-spaces)


108-108: Remove Trailing Spaces
Trailing spaces were detected on this line. Removing them will help maintain compliance with YAML lint rules.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 108-108: trailing spaces

(trailing-spaces)

Dockerfile (2)

2-2: Base Image Downgrade Verification
The base image has changed from node:22-bookworm-slim to node:20-slim. Please verify that this downgrade does not adversely affect the application’s runtime requirements or dependency compatibility.


81-85: Directory Creation and Permissions for Libvirt User
Creating the configuration directory in /home/libvirt/.config/libvirt and setting ownership with chown -R libvirt:libvirt is appropriate. Just ensure that these permissions meet the minimum requirements for required functionality without overexposing the system.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 3f865a3 and 20ea85a.

📒 Files selected for processing (4)
  • .github/workflows/main.yml (2 hunks)
  • Dockerfile (1 hunks)
  • __tests__/helpers.ts (1 hunks)
  • scripts/test-docker.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/test-docker.sh
🧰 Additional context used
🧬 Code Definitions (1)
__tests__/helpers.ts (2)
lib/hypervisor.ts (1)
  • Hypervisor (13-316)
lib/types.ts (1)
  • HypervisorOptions (4-6)
🪛 actionlint (1.7.4)
.github/workflows/main.yml

93-93: shellcheck reported issue in this script: SC2046:warning:32:8: Quote this to prevent word splitting

(shellcheck)

🪛 YAMLlint (1.35.1)
.github/workflows/main.yml

[error] 96-96: trailing spaces

(trailing-spaces)


[error] 108-108: trailing spaces

(trailing-spaces)

🔇 Additional comments (11)
__tests__/helpers.ts (4)

1-7: Import statements and constants look good.

The import statements are clean and focused, bringing in necessary dependencies for the test helpers. The constants for VM name and disk image path are well-defined.


58-86: Thorough QEMU installation verification.

The function effectively validates the QEMU installation, providing clear error messages when components are missing. The platform-specific error guidance for macOS is particularly helpful.

One improvement would be to return the full archConfig as you're already computing it, instead of returning it only after verification.


179-189: Disk image creation looks good.

The function properly creates a disk image for testing and has appropriate error handling.


191-212: Test environment setup function is well-structured.

The function orchestrates the setup process in a logical sequence:

  1. Clean up existing resources
  2. Create new resources
  3. Connect to the hypervisor
  4. Verify the environment

Returning both the connection and architecture configuration is helpful for test cases.

.github/workflows/main.yml (2)

42-43: Expanded APT Package Caching
The caching step now includes additional packages (qemu-system and qemu-user-static) alongside libvirt-dev, which is a beneficial enhancement for integration tests involving virtualization components.


75-84: Addition of Docker Buildx and QEMU Setup
The new steps to set up Docker Buildx and QEMU ensure support for multi-architecture builds. This setup appears correct and will help in building and testing images for both amd64 and arm64.

Dockerfile (5)

8-12: Build Stage Dependency Installation
The commands installing build dependencies (e.g., build-essential, python3, libvirt-dev) and subsequent cleanup with rm -rf /var/lib/apt/lists/* are well structured, helping to keep the image lean.


38-49: Enhanced Test Stage Dependencies
In the test stage, additional packages related to QEMU, OVMF, and libvirt (e.g., qemu-system-x86, qemu-system-arm, libvirt-daemon-system) have been added. This comprehensive dependency set should provide robust support for multi-architecture and virtualization tests.


51-57: Non-Root User and Permission Setup for Libvirt
The Dockerfile creates a non-root user libvirt, adds it to the kvm group, and sets up the required directories. This is a good practice for minimizing potential security risks.


75-78: Libvirt Configuration & Security Considerations
Libvirt’s configuration is now set up by appending values to /etc/libvirt/libvirtd.conf. Note that auth_unix_rw = "none" disables authentication for read/write access. This setting carries inherent security risks if the container were ever to run in an uncontrolled environment.


90-90: Container Startup Command Robustness
The CMD launches the libvirt daemon and then runs tests after a fixed delay (sleep 2). Verify that the sleep interval reliably allows enough time for libvirtd to initialize under various conditions. You might consider implementing a health check loop rather than a fixed sleep.

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 (5)
__tests__/domain-listing.test.ts (2)

9-11: Avoid using any type for better type safety.

The connection and archConfig variables are typed as any, which reduces TypeScript's ability to provide type checking and autocompletion. Consider using more specific types that match the expected structure of these objects.

-    let connection: any;
-    let domain: Domain | null = null;
-    let archConfig: any;
+    let connection: import('../lib').Hypervisor;
+    let domain: Domain | null = null;
+    let archConfig: {
+        arch: string;
+        machine: string;
+        emulator: string;
+    };

25-25: Consider using a more robust approach for waiting on domain state changes.

Fixed timeouts (1000ms) might be brittle if the test environment is slower than expected. Consider polling the domain state instead.

- await new Promise(resolve => setTimeout(resolve, 1000));
+ // Wait for domain to complete shutdown
+ let retries = 0;
+ while (retries < 10) {
+   try {
+     const info = await connection.domainGetInfo(domain);
+     if (info.state !== DomainState.RUNNING) {
+       break;
+     }
+   } catch (error) {
+     // Domain might no longer exist
+     break;
+   }
+   await new Promise(resolve => setTimeout(resolve, 500));
+   retries++;
+ }

Also applies to: 136-136

.github/workflows/main.yml (3)

95-101: Review Libvirt Directory Permission Settings
The step that creates libvirt directories with sudo privileges and applies chmod -R 777 is functionally correct in a CI context. However, since 777 permissions are generally considered insecure, it would be beneficial to add an inline comment clarifying that these permissions are acceptable only in the ephemeral CI environment and not recommended for production use.


102-146: Multi-Architecture Docker Integration Testing Workflow
The multi-arch Docker integration test block is comprehensive. It builds both "builder" and "test" stages, manages cache directories, and then runs container tests with the necessary privileges. For enhanced robustness, consider adding set -e (or a stricter shell configuration like set -euxo pipefail) at the beginning of the script block. This change would ensure that the step exits immediately if any command fails, improving error handling and debuggability.

Proposed diff snippet for the shell script block (for example, add on the first line of the script):

-run: |
+run: |
+  set -e
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 106-106: trailing spaces

(trailing-spaces)


[error] 118-118: trailing spaces

(trailing-spaces)


[error] 122-122: trailing spaces

(trailing-spaces)


106-106: Remove Trailing Whitespace
Static analysis has flagged the presence of trailing spaces on lines 106, 118, and 122. Please remove these extra spaces to adhere to YAML formatting standards.

Example diff for one of the lines:

-          mkdir -p test-artifacts    
+          mkdir -p test-artifacts

Also applies to: 118-118, 122-122

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 106-106: trailing spaces

(trailing-spaces)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 20ea85a and c6a3624.

📒 Files selected for processing (2)
  • .github/workflows/main.yml (2 hunks)
  • __tests__/domain-listing.test.ts (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
.github/workflows/main.yml

[error] 106-106: trailing spaces

(trailing-spaces)


[error] 118-118: trailing spaces

(trailing-spaces)


[error] 122-122: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (12)
__tests__/domain-listing.test.ts (5)

19-35: Clean domain state management in afterAll looks good.

The cleanup logic properly checks the domain state before attempting to shut it down and handles potential errors gracefully. This ensures that resources are properly released even if tests fail.


39-88: Well-structured domain description with comprehensive configuration.

The domain description provides a good example of API usage, covering essential VM configuration including memory, CPU, OS, and devices. This is valuable both as a test case and as documentation of the expected format.


94-97: Comprehensive testing of domain listing flags.

The test effectively validates the behavior of all important domain listing flags (ACTIVE, INACTIVE, RUNNING, PERSISTENT, TRANSIENT) and their combinations. Good use of array assertions to verify expected behavior.

Also applies to: 99-104, 109-114, 116-126, 128-133


127-133: Good use of bitwise operations for flag combination.

The test demonstrates how to correctly combine multiple flags using the bitwise OR operator, which is an important pattern when working with this API.


135-139: Proper test cleanup ensures test isolation.

The explicit cleanup at the end of the test ensures that resources are released even if the afterAll hook doesn't run, which helps maintain test isolation and prevents interference between test runs.

.github/workflows/main.yml (7)

42-44: Extended APT Cache Packages
The "Cache APT Packages" step now includes additional packages (qemu-system and qemu-user-static) along with libvirt-dev, which ensures that all dependencies required for the forthcoming libvirt and QEMU configurations are cached.


75-79: Set up Docker Buildx for Multi-Arch Builds
The integration of the Docker Buildx setup using docker/setup-buildx-action@v3 is correctly implemented. This is essential for handling multi-architecture image builds and aligns well with the new Docker integration testing strategy.


80-84: Set up QEMU for Architecture Emulation
The configuration for QEMU via docker/setup-qemu-action@v3 with the platforms linux/amd64,linux/arm64 is properly set up. This addition effectively supports the multi-arch builds in the later stages.


85-94: Caching Docker Build Cache for Improved Build Speeds
The Docker cache step is well-structured. The use of clearly defined keys and restore keys for both amd64 and arm64 caches should help in reducing rebuild times during image creation.


148-155: Save Docker Build Cache Step
The step dedicated to saving the updated Docker build caches for both architectures is correctly implemented. This will help subsequent builds leverage cached data and improve overall build efficiency.


156-163: Upload Test Artifacts
The step to upload test artifacts (with a retention period of 7 days) is clearly and correctly defined. It looks good as part of preserving build outputs for further analysis.


164-171: Upload Coverage Reports
The configuration for uploading coverage reports is properly set up to ensure that coverage data is preserved for review. This will help in later analysis and debugging if needed.

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 (3)
.github/workflows/main.yml (3)

85-91: Libvirt Directories Creation with Open Permissions.
The workflow creates the required libvirt directories and sets their permissions to 777 so that they are fully accessible. While this is acceptable in a CI environment, consider double-checking that such open permissions are appropriate and do not inadvertently introduce security issues if reused in a different context.


96-96: Trailing Whitespace Detected.
There are extraneous trailing spaces on this line. Removing these will ensure adherence to YAML style guidelines.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 96-96: trailing spaces

(trailing-spaces)


108-108: Trailing Whitespace Detected.
Please remove the trailing spaces on this line to maintain clean YAML formatting.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 108-108: trailing spaces

(trailing-spaces)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between c6a3624 and fcbe382.

📒 Files selected for processing (1)
  • .github/workflows/main.yml (2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
.github/workflows/main.yml

[error] 96-96: trailing spaces

(trailing-spaces)


[error] 108-108: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (8)
.github/workflows/main.yml (8)

42-44: APT Packages Update: Inclusion of QEMU Packages.
The caching step now includes qemu-system and qemu-user-static along with libvirt-dev. This change ensures that the necessary packages for multi-architecture Docker tests are pre-cached, which can help speed up the workflow execution.


75-79: Docker Buildx Setup Step.
This step sets up Docker Buildx (using docker/setup-buildx-action@v3) to facilitate multi-architecture builds. The configuration with install: true is appropriate and aligns with the new testing strategy.


80-84: QEMU Setup for Multi-Architecture Testing.
The new QEMU setup action enables support for both linux/amd64 and linux/arm64 platforms. This will help ensure that your Docker images build correctly across multiple architectures.


92-128: Comprehensive Docker Integration Tests Step.
This block implements integration tests that build and run Docker images for both amd64 and arm64 architectures. The loop structure, caching strategy (--cache-from and --cache-to), and the subsequent docker run command with the required volume mounts are well-constructed.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 96-96: trailing spaces

(trailing-spaces)


[error] 108-108: trailing spaces

(trailing-spaces)


130-137: Upload Test Artifacts Step.
The configuration for uploading test artifacts is clear, with a defined artifact name and a 7-day retention period. This helps in retaining crucial test output for troubleshooting and review.


138-144: Upload Coverage Reports Step.
This step correctly uploads coverage reports with the specified retention and artifact naming. The configuration is consistent with the overall artifact management strategy in the workflow.


146-150: NPM Authentication Setup.
The step that sets up NPM authentication for publishing is implemented in a secure and standard manner by redirecting the auth token to ~/.npmrc.


151-156: Publish to NPM Step.
The publishing step is conditionally executed based on the output of the release-please action, and it leverages the stored NPM authentication token. This configuration appears correct and follows best practices.

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)
__tests__/domain-lifecycle.test.ts (1)

171-173: ⚠️ Potential issue

Domain reference is prematurely cleared.

Setting domain = null in the finally block could interfere with the cleanup in the afterAll hook, which uses this reference to determine if cleanup is needed.

Remove this line to ensure proper cleanup in the afterAll hook:

        } finally {
            // Clear the domain reference before cleanup
-            domain = null;
        }
🧹 Nitpick comments (2)
__tests__/domain-cleanup.test.ts (2)

9-11: Consider adding type definitions for variables.

While using any type in test code is acceptable, consider adding more specific types for better code clarity and type safety.

-    let connection: any;
+    let connection: Hypervisor;
-    let archConfig: any;
+    let archConfig: ArchConfig;

99-141: Comprehensive test for domain undefining via hypervisor.

This test correctly verifies the hypervisor-based approach to undefining domains. However, there's significant code duplication with the previous test.

Consider refactoring the common domain creation and verification logic into a helper function to reduce duplication between these two tests.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between fcbe382 and 8e95d4f.

📒 Files selected for processing (4)
  • __tests__/domain-cleanup.test.ts (1 hunks)
  • __tests__/domain-lifecycle.test.ts (1 hunks)
  • __tests__/domain-listing.test.ts (1 hunks)
  • __tests__/hypervisor.test.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
__tests__/domain-cleanup.test.ts (3)
lib/types.ts (2)
  • Domain (130-130)
  • LibvirtError (132-159)
__tests__/helpers.ts (2)
  • setupTestEnv (192-212)
  • TEST_VM_NAME (6-6)
lib/domain-xml.ts (1)
  • domainDescToXml (300-412)
__tests__/domain-lifecycle.test.ts (3)
lib/types.ts (1)
  • Domain (130-130)
__tests__/helpers.ts (3)
  • setupTestEnv (192-212)
  • TEST_VM_NAME (6-6)
  • DISK_IMAGE (7-7)
lib/domain-xml.ts (1)
  • domainDescToXml (300-412)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (24)
__tests__/domain-cleanup.test.ts (6)

1-7: Appropriate imports for the test suite.

The imports correctly include all necessary modules for the domain cleanup tests - Vitest test framework, domain-related types and functions, and helper utilities.


13-17: Good test environment setup.

The beforeAll hook correctly sets up the test environment using the shared helper function. The timeout of 10 seconds provides sufficient time for the setup operations to complete.


19-35: Thorough domain cleanup before each test.

The beforeEach hook properly handles existing domain cleanup, including state checking, graceful shutdown, and undefining. The error handling is appropriate for a cleanup routine.


37-53: Proper resource cleanup after all tests.

The afterAll hook correctly manages resource cleanup, handling potential errors during the process. Good practice to set references to null after cleanup.


55-97: Well-structured test for domain undefining via domain object.

The test appropriately creates a domain configuration, defines it, verifies its existence, undefines it through the domain object's method, and then verifies its removal. The 60-second timeout provides adequate time for VM operations.


143-155: Good error handling test for non-existent domains.

The test appropriately validates the error handling behavior when attempting to work with non-existent domains, including checking the error type and properties.

__tests__/domain-lifecycle.test.ts (3)

1-7: Appropriate imports for lifecycle testing.

The imports correctly include all necessary modules for domain lifecycle tests, including the child_process module for executing system commands.


8-53: Well-structured test setup and teardown.

The setup and teardown hooks provide proper isolation for each test and handle resource cleanup appropriately.


55-170: Comprehensive VM lifecycle test.

The test thoroughly covers the domain lifecycle including creation, starting, and stopping. It properly handles firmware setup, XML generation, disk image creation, and VM state verification.

__tests__/domain-listing.test.ts (7)

1-7: Appropriate imports for domain listing tests.

The imports correctly include required modules for testing domain listing functionality, including the essential ConnectListAllDomainsFlags enum.


8-53: Well-structured test setup and teardown.

The lifecycle hooks appropriately manage the test environment setup and cleanup, following the same pattern as other test files for consistency.


55-106: Detailed domain configuration.

The test creates a comprehensive domain configuration with appropriate memory, CPU, OS, and device settings. The memory unit is explicitly set to KiB, which is a good practice for clarity.


108-122: Good verification of inactive domains.

The test correctly verifies domain creation and its presence in the inactive domains list before starting it.


123-132: Proper testing of running domains.

The test appropriately starts the domain and verifies its presence in the running domains list.


133-144: Comprehensive domain flags testing.

The test checks both persistent and transient domain flags, verifying expected behavior for the defined domain.


145-156: Proper cleanup after testing.

The test correctly cleans up resources after testing by shutting down and undefining the domain.

__tests__/hypervisor.test.ts (8)

1-7: Appropriate imports for hypervisor testing.

The imports include all necessary components for testing hypervisor functionality, including the DomainBuilder for creating domain configurations.


8-53: Well-structured test setup and teardown.

The test suite follows the established pattern for setup and teardown, maintaining consistency with other test files.


55-77: Good coverage of connection operations.

The test verifies essential hypervisor connection functionality like node information, maximum VCPUs, and hostname retrieval, with appropriate error handling for unsupported features.


79-129: Effective use of DomainBuilder.

The test utilizes the DomainBuilder pattern effectively to create a domain configuration, which is more maintainable than direct object creation.


130-182: Comprehensive domain management testing.

The test thoroughly covers domain lifecycle operations including creation, information retrieval, state management, and cleanup, with appropriate error handling validation.


184-196: Concise domain listing tests.

The test efficiently verifies all domain listing methods with appropriate type checking.


198-266: Thorough domain creation and lookup testing.

The test comprehensively verifies domain creation and lookup operations, including the use of the UUID for domain identification and proper error handling.


268-278: Good error case coverage.

The test thoroughly validates error handling for common failure scenarios like invalid XML, domain names, and UUIDs, ensuring proper error types are thrown.

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 (1)
.github/workflows/integration-test.yml (1)

33-39: Libvirt Directory Creation and Permissions
The script creates the required libvirt directories and sets permissions using chmod -R 777. While this approach is acceptable in a CI testing environment, it may be worth revisiting the permissiveness for improved security if this logic is ever used in a production-like context.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 8e95d4f and edece47.

📒 Files selected for processing (2)
  • .github/workflows/integration-test.yml (1 hunks)
  • .github/workflows/main.yml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/main.yml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Docker Integration Tests (arm64)
  • GitHub Check: Docker Integration Tests (amd64)
🔇 Additional comments (8)
.github/workflows/integration-test.yml (8)

1-9: Workflow Trigger Configuration Looks Good
The workflow is triggered on pushes, pull requests, and manual dispatch (workflow_dispatch) for the main branch. This comprehensive trigger setup ensures that integration tests run in all the required scenarios.


10-18: Job Definition and Matrix Strategy are Configured Properly
The docker-integration job definition leverages a matrix strategy to test on both amd64 and arm64 architectures. The use of fail-fast: false guarantees that tests for all defined platforms are executed even if one fails.


19-27: Checkout and Docker Buildx Setup are Implemented Correctly
Using actions/checkout@v4 ensures the repository is checked out cleanly, and the Docker Buildx setup with docker/setup-buildx-action@v3 (with install: true) is correctly configured to enable multi-platform builds.


28-32: QEMU Setup is Appropriately Configured
The step that sets up QEMU with docker/setup-qemu-action@v3 and explicitly specifies platforms (linux/amd64,linux/arm64) adequately prepares the environment for executing binaries across these architectures.


40-44: Dependencies Installation Step is Adequate
Updating the package list and installing qemu-user-static ensures that the runner is equipped to handle multi-architecture builds. This step is straightforward and correctly implemented.


45-59: Docker Build Command is Well Structured
The build step makes good use of Docker Buildx with multi-platform support. The use of --build-arg BASE_IMAGE=node:20-slim, caching parameters (--cache-from and --cache-to), and the --load flag helps in creating reproducible builds efficiently.


60-68: Container Run Step is Configured Correctly
The docker run command includes crucial flags such as --rm, --privileged, and correctly mounts volumes for the libvirt socket, libvirt directory, and test artifacts. This configuration ensures the container receives the necessary privileges and access to host directories during the test run.


69-75: Artifact Upload Step is Correctly Configured
Using the actions/upload-artifact@v4 step with an if: always() condition ensures that test artifacts are uploaded regardless of test results. Specifying a retention period of 7 days is appropriate for integration testing purposes.

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 (3)
README.md (3)

127-143: Updated Examples Section with pnpm Commands
The "Examples" section now clearly demonstrates how to use pnpm to run various domain operations (listing, starting, shutting down, and creating domains using the builder pattern).

Consider adding brief inline comments for each command to further clarify their purpose for new users.


147-158: Contribution Guidelines and Tone
The "Contribute" section has been updated with clear steps to install dependencies, run linting, and execute tests.

  • While the enthusiastic tone ("Any contribution is welcome!") is inviting, consider moderating the use of exclamation marks to maintain a professional tone (as suggested by LanguageTool).
  • Also, verify that legacy references (for example, "vmngr/libvirt contributers" in the copyright notice) are updated if the repository ownership has changed.
🧰 Tools
🪛 LanguageTool

[style] ~147-~147: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 2038 characters long)
Context: ... Contribute Any contribution is welcome! To check whether your contribution conf...

(EN_EXCESSIVE_EXCLAMATION)


186-194: Updated Badge Definitions
The badge URL definitions at the bottom of the file have been updated to reflect the new repository location (unraid/libvirt). This ensures consistency throughout the README.

It may be worth reviewing other sections (such as contributor notices) for similar legacy references.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between e21d123 and a67e052.

⛔ Files ignored due to path filters (1)
  • cover.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • README.md (4 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[style] ~147-~147: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 2038 characters long)
Context: ... Contribute Any contribution is welcome! To check whether your contribution conf...

(EN_EXCESSIVE_EXCLAMATION)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Docker Integration Tests (arm64)
  • GitHub Check: Docker Integration Tests (amd64)
🔇 Additional comments (7)
README.md (7)

7-8: Badge Additions for Tests and Coverage
The new "Tests" and "Coverage" badges have been added at these lines. They follow the established format and help improve the visibility of test status and code coverage.


13-14: Badge Additions for NPM Version and Last Update
The newly introduced badges for "NPM Version" and "Last Update" provide additional valuable information about the package state. Their inclusion is consistent with the other visual indicators.


84-85: Updated Debian/Ubuntu Installation Instructions
The installation command now includes qemu-system along with other essential packages. This update ensures that users on Debian/Ubuntu systems install all required dependencies.


93-94: Updated MacOS Installation Instructions
The MacOS installation command has been updated to install both libvirt and qemu using Homebrew, aligning with the new dependency requirements.


97-103: New Development Section Addition
A "Development" section has been added to guide contributors on using pnpm as the package manager. The instructions—including the global installation command (npm install -g pnpm)—are clear and useful.


105-110: Building Instructions Updated for pnpm
The "Building" section now instructs users to run pnpm install followed by pnpm build. This update is consistent with the project’s switch to pnpm and provides clear guidance.


112-122: Testing Instructions Updated for Vitest
The updated testing instructions now leverage Vitest commands (pnpm test, pnpm test:coverage, and pnpm test:ui). This not only clarifies the testing strategy but also aligns with the corresponding changes in the test framework.

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)
Dockerfile (2)

7-12: Installation of Build Dependencies
The build stage properly installs essential packages (build-essential, python3, and libvirt-dev). For enhanced reproducibility, consider pinning critical package versions if you encounter any build inconsistencies over time.


89-90: libvirtd Startup and Test Execution
Using sleep 2 after starting libvirtd is a quick fix to allow the daemon to initialize. However, this static delay may be unreliable under varying system loads. Consider implementing a dynamic wait (e.g., checking for an open socket or a readiness flag) to ensure libvirtd has started before running pnpm test:coverage.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between a67e052 and c46d209.

📒 Files selected for processing (2)
  • .github/workflows/integration-test.yml (1 hunks)
  • Dockerfile (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/integration-test.yml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Docker Integration Tests (arm64)
  • GitHub Check: Docker Integration Tests (amd64)
🔇 Additional comments (13)
Dockerfile (13)

1-2: Base Image and Stage Naming Update
The builder stage now uses node:20-slim (with stage alias builder) instead of the previous node:22-bookworm-slim. Please verify that this downgrade is intentional and that all dependencies and build scripts remain compatible with Node.js 20.


4-6: Set Non-Interactive Environment Variable
Defining DEBIAN_FRONTEND=noninteractive is an excellent choice to suppress interactive prompts during package installation.


15-20: Caching Package Files for Efficient Builds
Copying package*.json and pnpm-lock.yaml prior to the source files optimizes the build cache. This is a standard best practice that helps speed up subsequent builds.


21-24: Installing pnpm and Project Dependencies
Installing pnpm globally and then invoking pnpm install --frozen-lockfile is clear and effective for managing dependencies.


25-29: Copying Source Files and Building the Project
Copying the full source and executing the build command (pnpm run build) adheres to a robust multi-stage build strategy.


32-33: Test Stage Base Image Consistency
The test stage also uses node:20-slim, ensuring consistency between build and test environments.


34-50: Installing Test Dependencies
The test stage installs a comprehensive set of dependencies including various QEMU packages and libvirt tools, which are crucial for your integration tests. Please verify that these packages are fully supported on the chosen base image and meet your test requirements.


51-57: Non-root User Setup for libvirt
Creating a non-root user (libvirt) and adding it to the kvm group, with appropriate directory permissions for /var/run/libvirt, enhances the container’s security posture.


59-66: Test Environment Dependency Installation
Repeating the dependency installation steps in the test stage (copying package files, installing pnpm, and running dependency installs) ensures that the test environment is self-contained. This mirrors the build stage, which is typical in multi-stage Docker builds.


67-73: Transferring Build Artifacts and Test Files
Copying built files and configuration (from /app/dist, /app/lib, and test folders) from the builder stage into the test stage is correctly implemented to reuse artifacts.


74-78: Setting Up libvirt Configuration
The Dockerfile configures libvirt by updating /etc/libvirt/libvirtd.conf with settings like unix_sock_group and unix_sock_rw_perms, and notably sets auth_unix_rw to "none". A previous review raised concerns regarding the security implications of disabling authentication for the read-write socket. Please revalidate that this configuration is safe given your container environment.


80-85: User Directories and Permissions Setup
Creating the directory /home/libvirt/.config/libvirt with a default configuration file and setting the correct ownership for both this directory and /app is implemented well.


86-88: Switching to a Non-root User
Switching to the non-root libvirt user before executing the final command reinforces container security practices.

@elibosley elibosley changed the title Fix/major api improvements feat/major api improvements Mar 30, 2025
@codecov
Copy link

codecov bot commented Mar 30, 2025

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

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 (1)
README.md (1)

147-158: Contribution Guidelines Enhancement
The instructions for contributing now cover installing dependencies, linting, and testing. This sets clear expectations for contributors.
Consider toning down the exclamation mark in the opening sentence for a more formal, professional tone. For example:

-Any contribution is welcome! To check whether your contribution conforms to our style guide, run the following tasks:
+Any contribution is welcome. To check whether your contribution conforms to our style guide, run the following tasks:
🧰 Tools
🪛 LanguageTool

[style] ~147-~147: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 2036 characters long)
Context: ... Contribute Any contribution is welcome! To check whether your contribution conf...

(EN_EXCESSIVE_EXCLAMATION)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between b1e3926 and b5e6e4e.

📒 Files selected for processing (2)
  • .github/workflows/integration-test.yml (1 hunks)
  • README.md (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/integration-test.yml
🧰 Additional context used
🪛 LanguageTool
README.md

[style] ~147-~147: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 2036 characters long)
Context: ... Contribute Any contribution is welcome! To check whether your contribution conf...

(EN_EXCESSIVE_EXCLAMATION)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Docker Integration Tests (arm64)
  • GitHub Check: Docker Integration Tests (amd64)
🔇 Additional comments (9)
README.md (9)

7-8: New Badge Additions: Tests and Codecov
The addition of the "Tests badge" and "Codecov badge" enhances visibility into your project's testing status and code coverage. The URLs are correctly updated to point to the new repository location under unraid.


13-14: New Badge Additions: NPM Version and Last Update
These badges provide clear insights into the current published package version and the timestamp of the last commit. Their inclusion aids users in quickly assessing the project's state.


83-86: Updated Installation Instructions for Debian/Ubuntu
The installation command now includes qemu-system, which aligns with the updated Docker integration and testing requirements. This change improves clarity and ensures that users install all necessary dependencies for the library to work correctly.


92-95: Updated Installation Instructions for MacOS
The revised command now installs both libvirt and qemu via Homebrew. This update matches the new dependency requirements and ensures consistency with the Debian/Ubuntu instructions.


97-103: Addition of the Development Section
Introducing a dedicated "Development" section with instructions for using pnpm helps clearly differentiate between using the package as a consumer (via npm) and contributing to its development (via pnpm). The guidance is concise and appropriately placed.


107-110: Building Commands Using pnpm
The build instructions are straightforward, instructing users to install dependencies and build the project using pnpm. This aligns well with the newly introduced development practices.


116-125: Enhanced Testing Instructions
The testing section now provides commands for running tests, generating coverage reports, and launching a UI for tests. This comprehensive set of instructions will help contributors verify changes and ensure quality.


131-143: Updated Examples Section
The examples section now details various commands (listing domains, starting, shutting down, and using the builder pattern) that demonstrate the library's functionality. These clear examples will be very helpful for new users.


186-194: Updated Badge Definitions in the Footer
The badge URLs have been updated to reflect the move from vmngr to unraid, ensuring consistency throughout the documentation. These changes improve the accuracy of repo references for License, CI, Tests, Codecov, and more.

@elibosley elibosley changed the title feat/major api improvements feat!/major api improvements Mar 30, 2025
@elibosley elibosley merged commit 9b0413f into main Mar 30, 2025
3 of 4 checks passed
@elibosley elibosley deleted the fix/major-api-improvements branch March 30, 2025 00:48
elibosley added a commit that referenced this pull request Mar 30, 2025
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

- **New Features**
- Introduced asynchronous operations for virtual machine domain
management, enabling smoother domain destruction and removal.
- Added a new shell script for Docker-based integration testing across
multiple architectures.
- Added new methods for domain management in the hypervisor context,
including domain destruction and undefining.
- Introduced a `Domain` class for comprehensive management of virtual
machine instances.
- Added a new GitHub Actions workflow for automated Docker integration
tests across multiple architectures.

- **Enhancements**
- Improved Docker container configuration with a secure non-root user
setup for safer deployments.
- Expanded integration tests across multiple architectures and enhanced
error handling to provide clearer feedback and improved reliability.
- Enhanced XML serialization and deserialization processes for domain
configurations, improving robustness against edge cases.
- Updated testing framework to utilize Vitest, replacing previous
testing tools and enhancing coverage reporting.
- Added detailed documentation for several interfaces and enums to
improve clarity.
- Updated README with new badges and installation instructions, along
with a new "Development" section.

- **Chores**
- Updated CI and dependency management to boost build stability and
overall system consistency.
- Introduced a new testing configuration for Vitest to streamline test
execution and coverage reporting.
- Updated system requirements in package management for better
compatibility.
- Modified `.gitignore` to include new entries for coverage and test
artifacts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
elibosley pushed a commit that referenced this pull request Mar 30, 2025
🤖 I have created a release *beep* *boop*
---


## [2.0.0](v1.2.2...v2.0.0)
(2025-03-30)


### ⚠ BREAKING CHANGES

* major api improvements
([#37](#37))

### Features

* major api improvements
([#37](#37))
([5b7fa01](5b7fa01))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants