Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions .github/actions/check-nvx-rs/action.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Check nvx-rs
description: >-
Format, lint, document, and test the nvx crate, and the runtime adapter that builds on it
as an independent adapter
Format, lint, document, and test the nvx crate, check its public API against the snapshots
that adapters build on, and check the runtime adapter that builds on it as an independent
adapter

inputs:
toolchain:
Expand Down Expand Up @@ -186,3 +187,42 @@ runs:
--features guest --target x86_64-unknown-linux-musl
cargo "+${{ steps.toolchains.outputs.msrv }}" check --locked --all-targets \
--features guest --target x86_64-unknown-linux-musl

# The public API of nvx in each configuration that adapters build on must match the
# snapshots in tests/public-api; see its README. The check lists every target of each
# configuration, so it runs once, on Linux. cargo-public-api publishes no binaries, so dev
# pushes cache the build of the release that the script pins.
- name: Restore the public API tools
id: public-api-tools
if: runner.os == 'Linux'
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/public-api-tools
key: public-api-tools-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('scripts/check_public_api.py') }}

- name: Install the public API tools
if: runner.os == 'Linux'
shell: bash
env:
TOOLS: ${{ runner.temp }}/public-api-tools
run: |
set -euo pipefail
python3 scripts/check_public_api.py --install-tools --root "${TOOLS}"
echo "${TOOLS}/bin" >> "${GITHUB_PATH}"

- name: Save the public API tools
if: >-
success() &&
github.event_name == 'push' &&
github.ref == 'refs/heads/dev' &&
runner.os == 'Linux' &&
steps.public-api-tools.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/public-api-tools
key: ${{ steps.public-api-tools.outputs.cache-primary-key }}

- name: Check the public API of nvx
if: runner.os == 'Linux'
shell: bash
run: python3 scripts/check_public_api.py
4 changes: 2 additions & 2 deletions .github/actions/validate-nvx/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ runs:
set -euo pipefail
python3 -m pip install --requirement scripts/setup/azure/requirements.txt
python3 -m compileall -q scripts
python3 -m unittest scripts/test_performance.py scripts/test_nvx_tools.py scripts/test_guest_binaries.py scripts/test_microvm_tests.py scripts/test_development_release.py scripts/test_host_telemetry.py scripts/test_time_abi.py scripts/test_tool_versions.py scripts/test_markdown_links.py scripts/test_setup_azure.py -v
python3 -m unittest scripts/test_performance.py scripts/test_nvx_tools.py scripts/test_guest_binaries.py scripts/test_microvm_tests.py scripts/test_development_release.py scripts/test_host_telemetry.py scripts/test_time_abi.py scripts/test_tool_versions.py scripts/test_markdown_links.py scripts/test_public_api.py scripts/test_setup_azure.py -v
python3 scripts/test_adversarial.py -v
python3 .github/skills/nvx-host-connect/scripts/test_hosts.py -v
python3 scripts/nvx.py --help
Expand All @@ -33,7 +33,7 @@ runs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python -m compileall -q scripts
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python -m unittest scripts/test_performance.py scripts/test_nvx_tools.py scripts/test_guest_binaries.py scripts/test_microvm_tests.py scripts/test_development_release.py scripts/test_host_telemetry.py scripts/test_time_abi.py scripts/test_tool_versions.py scripts/test_markdown_links.py scripts/test_setup_azure.py -v
python -m unittest scripts/test_performance.py scripts/test_nvx_tools.py scripts/test_guest_binaries.py scripts/test_microvm_tests.py scripts/test_development_release.py scripts/test_host_telemetry.py scripts/test_time_abi.py scripts/test_tool_versions.py scripts/test_markdown_links.py scripts/test_public_api.py scripts/test_setup_azure.py -v
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python scripts\test_adversarial.py -v
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Expand Down
5 changes: 4 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
changes under `nvx-rs/`, those in [check-nvx-rs](./actions/check-nvx-rs/action.yml)
and, because `aci_edge_sandboxes` builds on the `nvx` crate there, check-aci-edge-sandboxes too.
check-nvx-rs also checks the runtime adapter in `tests/runtime-adapter/`, which
builds on `nvx`; run its steps for changes to either.
builds on `nvx`; run its steps for changes to either. On Linux, it also checks the
public API of `nvx` against `tests/public-api/`; after a deliberate API change, run
`python3 scripts/check_public_api.py --update`, which needs the tools that
`--install-tools` installs, and commit the snapshots.
They need no hypervisor. `scripts/nvx.py test-aci-edge-sandboxes` exercises both
crates on a real hypervisor.
- OpenVMM source changes also require the package-scoped checks prescribed by the
Expand Down
24 changes: 24 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
Say what changed and why. Start with "Closes #N" or "Fixes #N" when the pull
request completes an issue, and "Part of #N" or "Refs #N" otherwise; see
doc/contribute.md for the conventions.
-->

## Validation

<!--
List the checks that you ran, and the gates that you leave to CI, such as
backends that you could not test.
-->

## Adapter contract

Does this change the adapter contract (public API, behavior, persisted formats or wire)? If so, add a migration note and conformance cases.

<!--
Answer "No", or describe the change and how adapters migrate, and name the
conformance cases that cover it. CI checks the public API of nvx that
adapters build on against tests/public-api: when it changes, run
`python3 scripts/check_public_api.py --update` and commit the snapshots with
the change.
-->
14 changes: 14 additions & 0 deletions doc/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,20 @@ enables only its side of `nvx`, the guest-only build pulls in neither Tokio
nor a dependency that only the host side declares, and the guest binary is a
static executable.

On Linux, the `nvx-rs` job also checks the public API of `nvx` in each of
these configurations against the
[snapshots in `tests/public-api`](../tests/public-api/README.md).
[`check_public_api.py`](../scripts/check_public_api.py) lists the API of each
configuration on each of its targets, `x86_64-unknown-linux-gnu` and
`x86_64-pc-windows-msvc` for the protocol-only and host-only ones and
`x86_64-unknown-linux-musl` for the guest-only one, with the cargo-public-api
release and nightly toolchain that it pins. It fails on any difference from
the snapshots, additions included, and reports the size of each listing in the
job summary. cargo-public-api publishes no binaries, so `dev` pushes cache its
build under the hash of the script. A pull request that changes the API
updates the snapshots and answers the adapter-contract question of the
[pull request template](../.github/pull_request_template.md).

The development release job depends on `aci-edge-sandboxes` and `nvx-rs` and
requires their combined Linux/Windows results to be successful; failed,
cancelled, or skipped crate checks cannot publish a release. Before it uploads
Expand Down
3 changes: 2 additions & 1 deletion doc/contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ and a maintainer stages it on a `microsoft/nvx` branch to run the rest; see
| Commit subject | `area: summary`, where `area` is the component, command, or directory that changes, such as `doc`, `ci`, `guest`, `sandbox`, or `openvmm`. Start the summary with a lowercase imperative verb and omit the trailing period: `ci: run each OpenVMM suite only when its inputs change`. |
| Commit body | What changed and why, when the subject does not say enough. |
| Pull request title | The commit subject of a single-commit pull request; otherwise a summary in the same form. |
| Pull request body | What changed and why, then a `Validation` section that lists the checks you ran and the gates you leave to CI, such as backends you could not test. |
| Pull request body | What changed and why, then a `Validation` section that lists the checks you ran and the gates you leave to CI, such as backends you could not test, and the answer to the adapter-contract question of the [pull request template](../.github/pull_request_template.md). A change to the adapter contract carries a migration note and conformance cases, and a change to the public API of `nvx` updates its [snapshots](../tests/public-api/README.md). |
| Issue references | `Closes #N` or `Fixes #N` first when the pull request completes the issue; `Part of #N` or `Refs #N` otherwise. |
| Review threads | Reply with the commit that addresses the comment, or with the evidence that no change is needed, then resolve the thread. |

Expand Down Expand Up @@ -77,6 +77,7 @@ the Python, shell, and link checks.
| `aci_edge_sandboxes/` | rustfmt, Clippy and rustdoc with warnings denied, tests, and the minimum supported Rust version; see [Rust crates](ci.md#rust-crates) | [check-aci-edge-sandboxes](../.github/actions/check-aci-edge-sandboxes/action.yml) |
| `nvx-rs/` | rustfmt, Clippy and rustdoc with warnings denied, tests including a bundled-release fixture, the minimum supported Rust version, a macOS check, and, through `nvx.py`, the musl lint, tests, build, digest manifest, and static-ELF check of the guest binaries; see [Rust crates](ci.md#rust-crates) | [check-nvx-rs](../.github/actions/check-nvx-rs/action.yml) |
| `tests/runtime-adapter/` | rustfmt, then Clippy with warnings denied, the build, the tests, and the minimum supported Rust version of `nvx`, in the protocol-only, host-only, and, on Linux, static musl guest-only configurations; see [Rust crates](ci.md#rust-crates) | [check-nvx-rs](../.github/actions/check-nvx-rs/action.yml) |
| Public API of `nvx` | On Linux, the public API of the protocol-only, host-only, and guest-only configurations on each of their targets, against the snapshots in `tests/public-api`, with pinned tools; `python3 scripts/check_public_api.py --update` rewrites the snapshots; see [Public API snapshots](../tests/public-api/README.md) | [check-nvx-rs](../.github/actions/check-nvx-rs/action.yml), [check_public_api.py](../scripts/check_public_api.py) |
| NVX CLI | Compiles `scripts/`, runs every `scripts/test_*.py` module, and checks command help, on Linux and Windows | [validate-nvx](../.github/actions/validate-nvx/action.yml) |

check-quality names each shell script that it checks, and a CLI test fails
Expand Down
18 changes: 14 additions & 4 deletions doc/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ are build products or caches and are not part of the tracked source tree. The
| `aci_edge_sandboxes` | Rust crate `aci_edge_sandboxes`: state-aware sandbox API with an OpenVMM backend and an opt-in native-agent backend |
| `nvx-rs` | Rust crate `nvx`: the NVX mechanics that the OpenVMM backend builds on |
| `tests/runtime-adapter` | Rust crate `runtime-adapter`: an independent adapter that CI builds against `nvx` through its public API |
| `tests/public-api` | Snapshots of the public API of `nvx` that adapters build on, which CI checks |
| `openvmm` | Public OpenVMM Git submodule from `microsoft/openvmm`, tracking its `feature/microvm/dev` branch |
| `data` | Tracked performance history and generated benchmark data |
| `scripts/nvx_tools` | Implementation of the `nvx.py` commands |
Expand Down Expand Up @@ -51,7 +52,8 @@ nvx/
| | |-- run-platform.yml Reusable platform benchmark and package job
| | `-- specula-release.yml Specula verification of published releases
| |-- actionlint.yaml Self-hosted runner labels for actionlint
| `-- copilot-instructions.md Repository-wide Copilot instructions
| |-- copilot-instructions.md Repository-wide Copilot instructions
| `-- pull_request_template.md Pull request description template
|-- .vscode/settings.json Shared VS Code settings
|-- guest/ Guest-owned scripts
| |-- common/ Shared init, agent, snapshot, and probe scripts
Expand Down Expand Up @@ -154,12 +156,14 @@ nvx/
| | |-- setup-windows-whp.ps1 Windows/WHP development-host and Actions runner bootstrap
| | `-- tool-versions.conf Shared tool release and checksum pins
| |-- check_markdown_links.py Markdown link, anchor, and doc/ path check run by CI
| |-- check_public_api.py Public API check of nvx run by CI
| |-- nvx-hosts.example.json Template for the ignored .nvx-hosts.json
| |-- nvx.py Supported command-line entry point
| |-- nvx_adversarial_executor.py Restricted adversarial executor entry point
| |-- publish_development_release.py Development release publisher run by CI
| `-- test_*.py Python tooling unit tests
|-- tests/ Tests that build on the repository's crates from outside them
| |-- public-api/ Snapshots of the public API of nvx that adapters build on
| `-- runtime-adapter/ Rust crate `runtime-adapter`, an independent adapter of nvx
| |-- src/ Its library, and its host and guest skeleton binaries
| `-- tests/ Consumer-contract scenario C0, the independent build
Expand Down Expand Up @@ -198,7 +202,9 @@ The `actions/` directory contains the reusable implementations for validation,
artifact builds, benchmarks, packaging, releases, and performance history
management. The `skills/` directory defines Copilot agent skills for common
development workflows, and `copilot-instructions.md` holds the repository-wide
Copilot instructions. The `specula/` directory contains the adapter, tests, and
Copilot instructions. `pull_request_template.md` prefills pull request
descriptions, including the question of whether a change touches the adapter
contract. The `specula/` directory contains the adapter, tests, and
dedicated runner setup for incremental formal verification of the pinned
OpenVMM release.

Expand Down Expand Up @@ -326,7 +332,9 @@ using the [tool manifest](../scripts/setup/tool-versions.conf);
see [Automated environment bootstrap](setup.md#automated-environment-bootstrap).
`nvx-hosts.example.json` is the template for the
[remote agent host](setup.md#remote-agent-hosts) inventory, and CI runs
`publish_development_release.py` to publish development releases.
`publish_development_release.py` to publish development releases and
`check_public_api.py` to check the public API of `nvx` against its
[snapshots](../tests/public-api/README.md).

### `tests/`

Expand All @@ -336,7 +344,9 @@ crate with its own `Cargo.lock` that depends on `nvx` with default features
off and uses its public API only. Its protocol-only, host-only, and guest-only
configurations build in CI, and its tests check that each one builds as an
independent adapter's does. See its
[README](../tests/runtime-adapter/README.md).
[README](../tests/runtime-adapter/README.md). `public-api/` records the public
API of `nvx` in the same configurations, which CI checks so that every
change to it shows in review; see its [README](../tests/public-api/README.md).

## Root files

Expand Down
Loading
Loading