Skip to content

tests: add the runtime adapter and run its checks in CI - #626

Merged
Enrique Saurez (esaurez) merged 1 commit into
devfrom
esaurez/a1-test-adapter-ci-20261019
Oct 20, 2026
Merged

Enrique Saurez (esaurez) merged 1 commit into
devfrom
esaurez/a1-test-adapter-ci-20261019

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds tests/runtime-adapter/, the in-repository test adapter of #535: an independent adapter that builds on nvx-rs the way an adapter outside the repository does. From this PR on, NVX's own CI proves that such an adapter builds against nvx-rs through its public API only, and a change to the adapter alone runs the microVM jobs. Later A1 steps (G6 and H5) fill it with real scenarios.

What changed

The crate, tests/runtime-adapter/:

  • It has its own Cargo.lock and no parent workspace, a path dependency on nvx-rs (library nvx) with default-features = false, the MSRV of nvx-rs (rust-version = "1.89"), and unsafe_code = "forbid".
  • Three configurations: protocol-only (no feature), host-only (--features host), and guest-only (--features guest --target x86_64-unknown-linux-musl).
  • runtime-adapter-host and runtime-adapter-guest are skeletons that print the contract they were built against: the control contract revision and the microVM ABI, NVXS, and NVXC versions, all from the public API.
  • The lockfile was seeded from nvx-rs/Cargo.lock, so it resolves the same registry versions as nvx-rs, without the dev-dependencies of nvx-rs.

C0 as tests, in tests/independent_build.rs, which every configuration runs:

  • The adapter is a workspace of its own with its own lockfile (cargo locate-project --workspace), and declares the MSRV of nvx-rs.
  • From cargo tree --locked on the lockfile: protocol-only depends on nvx-rs alone, with no feature; host-only enables host and not guest; guest-only, for musl, enables exactly guest, pulls in no tokio or tokio-* crate, and none of the dependencies that the host side of nvx-rs declares and its guest side doesn't. The tests read that set from the tree too: today serde, serde_json, and sha2.
  • The binaries run and print their contract, and refuse arguments with status 2. The guest binary is a static executable: no PT_INTERP, no DT_NEEDED, and a non-executable stack. A synthetic-ELF test checks that the checker detects each of these.

CI:

  • check-nvx-rs runs one step per configuration: rustfmt (once), Clippy with -D warnings, cargo build, cargo test, and cargo check with the MSRV toolchain. The guest-only step runs on Linux, where it adds the musl target to both toolchains.
  • CI_TEST_INPUT_PATHS in scripts/nvx_tools/ci.py now includes tests/runtime-adapter/. It is an input of neither OpenVMM suite. A new test in scripts/test_nvx_tools.py, next to the existing classification cases, classifies adapter-only changes and checks through required_ci_expected_results that the pull request expects every microVM job and skips both OpenVMM suites. It fails without the ci.py change.
  • run-nvx-microvm-tests.yml gets a placeholder hook, "Run runtime adapter scenarios on Linux/Windows": cargo test --locked --features host -- --ignored in the adapter, with NVX_HYPERVISOR set to the backend, which nvx::Hypervisor::from_env_or_default reads. The debug-kernel jobs skip it. The adapter has no ignored test yet, so the step only builds it; later steps add scenarios as ignored tests.
  • Documentation: doc/ci.md, doc/contribute.md, doc/project-structure.md, .github/copilot-instructions.md, and the adapter's README.

Not in this PR:

Part of #619. Refs #535, #620.

Validation

Started from dev at 4a6c3b6.

Windows 11, x86_64-pc-windows-msvc, Rust 1.95.0 and 1.89:

  • python scripts\nvx.py verify.
  • In tests/runtime-adapter, protocol-only and host-only: cargo fmt --all --check, cargo clippy --locked --all-targets [--features host] -- -D warnings, cargo build --locked, cargo test --locked (6 and 7 tests pass), and cargo +1.89 check --locked --all-targets.
  • In nvx-rs, NVX_BUNDLE=skip cargo test --locked --all-features passes; no nvx-rs file changed.
  • Ruff check and format, Pyright strict for the Linux and Windows platforms, and scripts/check_markdown_links.py.
  • The validate-nvx unit-test modules: 1,035 tests pass. The 18 failures are all in test_setup_azure and are environmental: this host's bash is the WSL launcher, which can't open the D:/ temporary paths; CI's Windows runner uses Git Bash. This PR changes none of the files that they test.
  • python scripts\nvx.py classify-ci-changes on an adapter-only file list: the pull request sets run-tests=true and run-workloads=true, and both OpenVMM suites false. A push sets all four true.

Linux, WSL Ubuntu on x86_64:

  • All three configurations, including guest-only for x86_64-unknown-linux-musl: Clippy, build, test (8 tests in guest-only), and cargo +1.89 check. The guest binary is static-pie, and nvx.py check-static-elf agrees.
  • The validate-nvx unit-test modules: 1,053 pass. test_adversarial.py has one failure, test_contained_native_process_preserves_child_signal_status, which fails the same way on unmodified dev under WSL.
  • Negative controls: each of these makes the matching test fail: the guest feature also enabling nvx-rs/host, the default features of nvx-rs turned on, a different declared MSRV, a guest binary built for glibc, and the classifier without the ci.py change.

I ran no hypervisor: the hook has no scenario yet. Left to CI: the microVM jobs on KVM, MSHV, and WHP, which exercise the hook, and the nvx-rs jobs on GitHub-hosted Linux and Windows, which run the adapter's checks.

Copilot AI balanced review requested due to automatic review settings October 20, 2026 06:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The scoped scaffolding, contract tests, and CI integration have no identified blocking issues.

No open issues 🎉

What changed in this PR

Adds an independent runtime adapter to verify that external consumers can build against nvx-rs through its public API, establishing the C0 foundation for later runtime scenarios.

Changes:

  • Adds protocol-only, host-only, and static musl guest-only configurations with contract tests.
  • Integrates adapter checks, change classification, and placeholder scenario hooks into CI.
  • Documents the adapter and contributor validation requirements.
File Description
tests/​runtime-adapter/​tests/​independent_build.rs Checks build independence, feature isolation, binaries, and static linkage.
tests/​runtime-adapter/​src/​lib.rs Reports public runtime contract versions.
tests/​runtime-adapter/​src/​bin/​runtime-adapter-host.rs Adds the host skeleton.
tests/​runtime-adapter/​src/​bin/​runtime-adapter-guest.rs Adds the guest skeleton.
tests/​runtime-adapter/​README.md Documents configurations, tests, and CI integration.
tests/​runtime-adapter/​Cargo.toml Defines the standalone adapter and feature configurations.
tests/​runtime-adapter/​Cargo.lock Pins independent dependency resolution.
scripts/​test_nvx_tools.py Tests adapter checks and CI routing.
scripts/​nvx_tools/​ci.py Classifies adapter changes as microVM test inputs.
doc/​project-structure.md Adds the adapter to the repository map.
doc/​contribute.md Documents adapter validation and test placement.
doc/​ci.md Explains adapter checks and scenario hooks.
.gitignore Excludes adapter build output.
.github/​workflows/​run-nvx-microvm-tests.yml Adds backend-specific hooks for future scenarios.
.github/​copilot-instructions.md Includes adapter checks in contributor guidance.
.github/​actions/​check-nvx-rs/​action.yml Validates all three adapter configurations.

Review effort: Balanced

Add tests/runtime-adapter, an independent adapter that builds on nvx-rs
the way an adapter outside the repository does: a path dependency with
default features off, a lockfile of its own, the public API only, and
the minimum Rust version of nvx-rs. Its protocol-only, host-only, and
guest-only configurations each select one side of nvx-rs, and the guest
one builds a static x86_64-unknown-linux-musl executable. Its host and
guest binaries are skeletons that later steps fill.

Its tests check consumer-contract scenario C0: the dependency tree of
each configuration, which cargo tree resolves from the lockfile; that
the guest build pulls in neither Tokio nor a dependency that only the
host side of nvx-rs declares; that the binaries run; and that the guest
binary is a static executable.

check-nvx-rs checks each configuration with rustfmt, Clippy, the build,
the tests, and the minimum Rust version. The microVM workflow gains a
hook that runs the adapter's ignored tests on each backend, which later
steps add, and the change classifier treats the adapter as a test input,
so that a change to the adapter alone runs the microVM jobs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b901ceb9-fff0-4a76-9f55-a4b07d9c0633

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No blocking issues remain within the clearly scoped adapter scaffolding and CI integration; tests were not executed during this review.

No open issues 🎉

Review effort: Balanced

@esaurez
Enrique Saurez (esaurez) merged commit c74aeae into dev Oct 20, 2026
34 checks passed
@esaurez
Enrique Saurez (esaurez) deleted the esaurez/a1-test-adapter-ci-20261019 branch October 20, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants