mirror of
https://github.com/wirenboard/agent-vm.git
synced 2026-07-09 16:00:54 +00:00
Merge branch 'b2-aarch64-binary' into integration-7feat
This commit is contained in:
commit
45655fb773
10 changed files with 262 additions and 18 deletions
15
.cargo/config.toml
Normal file
15
.cargo/config.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Cross-compilation linkers.
|
||||
#
|
||||
# The `agent-vm` binary and the patched `msb` link a handful of C
|
||||
# libraries (libcap-ng, libdbus, libsqlite3) plus the usual libc, so a
|
||||
# cross build needs the matching cross linker — the default `cc` only
|
||||
# knows how to emit host (x86_64) objects.
|
||||
#
|
||||
# CI (release-npm.yml, build-agent-vm/build-msb aarch64 matrix legs)
|
||||
# installs `gcc-aarch64-linux-gnu` for the linker and the arm64 dev
|
||||
# libraries (`libcap-ng-dev:arm64 libdbus-1-dev:arm64
|
||||
# libsqlite3-dev:arm64`, enabled via `dpkg --add-architecture arm64`)
|
||||
# so the final link resolves. Locally, install the same Debian/Ubuntu
|
||||
# packages to reproduce.
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
122
.github/workflows/release-npm.yml
vendored
122
.github/workflows/release-npm.yml
vendored
|
|
@ -62,6 +62,16 @@ jobs:
|
|||
- platform: linux-x64
|
||||
runner: ubuntu-latest
|
||||
cargo_target: x86_64-unknown-linux-gnu
|
||||
# linux-arm64 is cross-compiled on the x64 runner (GitHub's
|
||||
# hosted arm64 Linux runners aren't on the free tier).
|
||||
# `gcc-aarch64-linux-gnu` provides the cross linker (wired
|
||||
# up by the repo .cargo/config.toml); the arm64 dev libs the
|
||||
# final link needs come in via `dpkg --add-architecture
|
||||
# arm64` (see the install step).
|
||||
- platform: linux-arm64
|
||||
runner: ubuntu-latest
|
||||
cargo_target: aarch64-unknown-linux-gnu
|
||||
cross: true
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
|
@ -75,12 +85,28 @@ jobs:
|
|||
submodules: 'recursive'
|
||||
|
||||
- name: Install Rust toolchain + linux deps
|
||||
env:
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rustup toolchain install stable --profile minimal --no-self-update
|
||||
rustup target add ${{ matrix.cargo_target }}
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libcap-ng-dev libdbus-1-dev libsqlite3-dev pkg-config
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
# Enable the arm64 multiarch repo, then pull the cross
|
||||
# linker + arm64 builds of the C libs agent-vm /
|
||||
# microsandbox link (libcap-ng, libdbus, libsqlite3).
|
||||
# Without the `:arm64` dev libs the final link can't
|
||||
# resolve -lcap-ng / -ldbus-1 / -lsqlite3 for the target.
|
||||
sudo dpkg --add-architecture arm64
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-aarch64-linux-gnu pkg-config \
|
||||
libcap-ng-dev:arm64 libdbus-1-dev:arm64 libsqlite3-dev:arm64
|
||||
else
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libcap-ng-dev libdbus-1-dev libsqlite3-dev pkg-config
|
||||
fi
|
||||
|
||||
- name: Cargo cache (rust-cache)
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
|
@ -110,7 +136,20 @@ jobs:
|
|||
cache-workspace-crates: "true"
|
||||
|
||||
- name: cargo build --release -p agent-vm
|
||||
run: cargo build --release --target ${{ matrix.cargo_target }} -p agent-vm
|
||||
env:
|
||||
# Cross pkg-config: point at the arm64 .pc files and let
|
||||
# pkg-config run host→target (the `pkg-config` crate refuses
|
||||
# cross queries unless PKG_CONFIG_ALLOW_CROSS=1). No-ops on
|
||||
# the native x64 leg (CROSS unset).
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
export PKG_CONFIG_ALLOW_CROSS=1
|
||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
export PKG_CONFIG_SYSROOT_DIR=/
|
||||
fi
|
||||
cargo build --release --target ${{ matrix.cargo_target }} -p agent-vm
|
||||
|
||||
- name: Upload agent-vm binary
|
||||
uses: actions/upload-artifact@v7
|
||||
|
|
@ -129,6 +168,12 @@ jobs:
|
|||
- platform: linux-x64
|
||||
runner: ubuntu-latest
|
||||
cargo_target: x86_64-unknown-linux-gnu
|
||||
# linux-arm64 cross-build — see build-agent-vm for the
|
||||
# rationale (no free hosted arm64 Linux runner).
|
||||
- platform: linux-arm64
|
||||
runner: ubuntu-latest
|
||||
cargo_target: aarch64-unknown-linux-gnu
|
||||
cross: true
|
||||
runs-on: ${{ matrix.runner }}
|
||||
env:
|
||||
# Override vendor/microsandbox's `lto=true, codegen-units=1`
|
||||
|
|
@ -138,18 +183,34 @@ jobs:
|
|||
# runtime cost on a TLS-proxy workload.
|
||||
CARGO_PROFILE_RELEASE_LTO: "thin"
|
||||
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "16"
|
||||
# The superproject's .cargo/config.toml sets the aarch64 linker,
|
||||
# but it is NOT on the config search path when building from
|
||||
# vendor/microsandbox (a separate workspace), so set the linker
|
||||
# via env here too. No-op on the native x64 leg.
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install Rust toolchain + linux deps
|
||||
env:
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rustup toolchain install stable --profile minimal --no-self-update
|
||||
rustup target add ${{ matrix.cargo_target }}
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libcap-ng-dev libdbus-1-dev libsqlite3-dev pkg-config
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
sudo dpkg --add-architecture arm64
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-aarch64-linux-gnu pkg-config \
|
||||
libcap-ng-dev:arm64 libdbus-1-dev:arm64 libsqlite3-dev:arm64
|
||||
else
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libcap-ng-dev libdbus-1-dev libsqlite3-dev pkg-config
|
||||
fi
|
||||
|
||||
- name: Cargo cache (rust-cache)
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
|
@ -171,7 +232,15 @@ jobs:
|
|||
cache-workspace-crates: "true"
|
||||
|
||||
- name: cargo build --release -p microsandbox-cli --bin msb
|
||||
env:
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
export PKG_CONFIG_ALLOW_CROSS=1
|
||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
export PKG_CONFIG_SYSROOT_DIR=/
|
||||
fi
|
||||
cargo build --release --target ${{ matrix.cargo_target }} \
|
||||
--manifest-path vendor/microsandbox/Cargo.toml \
|
||||
-p microsandbox-cli --bin msb
|
||||
|
|
@ -199,6 +268,15 @@ jobs:
|
|||
- platform: linux-x64
|
||||
runner: ubuntu-latest
|
||||
arch: x86_64
|
||||
# linux-arm64: cross-build the kernel with ARCH=arm64 +
|
||||
# CROSS_COMPILE=aarch64-linux-gnu-. Needs the arm64 kbuild
|
||||
# .config seed patch (libkrunfw-overrides/
|
||||
# config-libkrunfw_aarch64.patch); the build step fails fast
|
||||
# with a clear message if that seed hasn't been ported yet.
|
||||
- platform: linux-arm64
|
||||
runner: ubuntu-latest
|
||||
arch: aarch64
|
||||
cross: true
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
|
@ -231,12 +309,20 @@ jobs:
|
|||
|
||||
- name: Install kernel build deps
|
||||
if: steps.lk-cache.outputs.cache-hit != 'true'
|
||||
env:
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential bc flex bison libelf-dev libssl-dev \
|
||||
kmod cpio bzip2 xz-utils python3 python3-pyelftools \
|
||||
curl ca-certificates patch
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
# Cross toolchain for the arm64 kernel build.
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-aarch64-linux-gnu
|
||||
fi
|
||||
|
||||
- name: Clone + patch + build libkrunfw
|
||||
if: steps.lk-cache.outputs.cache-hit != 'true'
|
||||
|
|
@ -244,11 +330,24 @@ jobs:
|
|||
env:
|
||||
LK_V: ${{ steps.lkv.outputs.libkrunfw_version }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
CROSS: ${{ matrix.cross && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# The arm64 leg cross-compiles the kernel. It needs an arm64
|
||||
# kbuild .config seed; bail early with a clear message rather
|
||||
# than silently emit a kernel built with the wrong config.
|
||||
if [[ -n "$CROSS" && ! -f "libkrunfw-overrides/config-libkrunfw_${ARCH}.patch" ]]; then
|
||||
echo "::error::libkrunfw-overrides/config-libkrunfw_${ARCH}.patch is missing — the arm64 libkrunfw kernel config seed has not been ported yet (see B2 notes)."
|
||||
exit 1
|
||||
fi
|
||||
git clone --branch "v${LK_V}" --depth 1 \
|
||||
https://github.com/containers/libkrunfw.git libkrunfw-src
|
||||
cd libkrunfw-src
|
||||
# Cross build env for arm64: make picks up ARCH/CROSS_COMPILE.
|
||||
if [[ -n "$CROSS" ]]; then
|
||||
export ARCH=arm64
|
||||
export CROSS_COMPILE=aarch64-linux-gnu-
|
||||
fi
|
||||
# 1) kbuild .config seed (CONFIG_KVM=y + Intel/AMD backends).
|
||||
patch -p1 < ../libkrunfw-overrides/config-libkrunfw_${ARCH}.patch
|
||||
# 2) Kernel source patches: libkrunfw's Makefile runs
|
||||
|
|
@ -303,6 +402,9 @@ jobs:
|
|||
- platform: linux-x64
|
||||
runner: ubuntu-latest
|
||||
libkrunfw_arch: x86_64
|
||||
- platform: linux-arm64
|
||||
runner: ubuntu-latest
|
||||
libkrunfw_arch: aarch64
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
|
@ -419,6 +521,12 @@ jobs:
|
|||
name: agent-vm-linux-x64
|
||||
path: npm-dist/agent-vm-linux-x64/
|
||||
|
||||
- name: Download linux-arm64 artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: agent-vm-linux-arm64
|
||||
path: npm-dist/agent-vm-linux-arm64/
|
||||
|
||||
- name: Verify artifact layout + restore executable bits
|
||||
# `actions/upload-artifact@v7` packs files into a zip that
|
||||
# doesn't preserve POSIX permissions. After download, the
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@ Templates and tooling for distributing `agent-vm` via npm.
|
|||
and `execve`s the prebuilt native binary from the matching
|
||||
per-platform subpackage. Declares per-platform subpackages as
|
||||
`optionalDependencies` so npm installs only the right one.
|
||||
- `agent-vm-linux-x64/` — per-platform subpackage. Ships the
|
||||
prebuilt `bin/agent-vm`, the patched `bin/msb`, and
|
||||
`lib/libkrunfw.so.5.2.1`. agent-vm finds `msb` and `libkrunfw` via
|
||||
`current_exe()`-relative paths so a user's separate microsandbox
|
||||
install never shadows them.
|
||||
- Future per-platform subpackages: `-linux-arm64`, `-darwin-arm64`,
|
||||
`-darwin-x64`, `-win32-x64`. Add to the launcher's
|
||||
`PLATFORM_PACKAGES` map and to the main package's
|
||||
`optionalDependencies`.
|
||||
- `agent-vm-linux-x64/`, `agent-vm-linux-arm64/` — per-platform
|
||||
subpackages. Each ships the prebuilt `bin/agent-vm`, the patched
|
||||
`bin/msb`, and `lib/libkrunfw.so.5.2.1`. agent-vm finds `msb` and
|
||||
`libkrunfw` via `current_exe()`-relative paths so a user's separate
|
||||
microsandbox install never shadows them.
|
||||
- Future per-platform subpackages: `-darwin-arm64`, `-darwin-x64`,
|
||||
`-win32-x64`. Add to the launcher's `PLATFORM_PACKAGES` map and to
|
||||
the main package's `optionalDependencies`.
|
||||
|
||||
## How releases happen
|
||||
|
||||
|
|
|
|||
9
npm-dist/agent-vm-linux-arm64/README.md
Normal file
9
npm-dist/agent-vm-linux-arm64/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# @wirenboard/agent-vm-linux-arm64
|
||||
|
||||
Prebuilt `agent-vm` binary + patched `msb` + libkrunfw for linux/arm64.
|
||||
|
||||
You don't install this directly. The user-facing package is
|
||||
[`@wirenboard/agent-vm`](https://www.npmjs.com/package/@wirenboard/agent-vm),
|
||||
which pulls this in as an `optionalDependency` on linux/arm64 hosts.
|
||||
|
||||
Source: <https://github.com/wirenboard/agent-vm>.
|
||||
0
npm-dist/agent-vm-linux-arm64/bin/.gitkeep
Normal file
0
npm-dist/agent-vm-linux-arm64/bin/.gitkeep
Normal file
0
npm-dist/agent-vm-linux-arm64/lib/.gitkeep
Normal file
0
npm-dist/agent-vm-linux-arm64/lib/.gitkeep
Normal file
22
npm-dist/agent-vm-linux-arm64/package.json
Normal file
22
npm-dist/agent-vm-linux-arm64/package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "@wirenboard/agent-vm-linux-arm64",
|
||||
"version": "0.0.0",
|
||||
"description": "agent-vm prebuilt binary + patched msb + libkrunfw for linux-arm64.",
|
||||
"homepage": "https://github.com/wirenboard/agent-vm",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wirenboard/agent-vm.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"],
|
||||
"files": [
|
||||
"bin/agent-vm",
|
||||
"bin/msb",
|
||||
"lib/libkrunfw.so.*",
|
||||
"README.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
90
npm-dist/agent-vm/bin/agent-vm.dispatch.test.js
Normal file
90
npm-dist/agent-vm/bin/agent-vm.dispatch.test.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env node
|
||||
// Deterministic dispatch test for the npm launcher (bin/agent-vm.js).
|
||||
//
|
||||
// Why this exists: the launcher's job is to map the running
|
||||
// platform/arch to a per-platform subpackage and then build the
|
||||
// `bin/agent-vm` path inside it. arm64 was added to that mapping in
|
||||
// B2, but arm64 dispatch cannot be exercised on an x86_64 CI host —
|
||||
// `node` reports the host's real process.arch, so simply running the
|
||||
// launcher there only ever exercises the linux-x64 leg. This test
|
||||
// closes that gap without a real arm64 runtime by re-deriving the
|
||||
// mapping + path logic from the launcher source and asserting the
|
||||
// linux-arm64 key resolves to the expected package and to the same
|
||||
// bin/ layout as linux-x64.
|
||||
//
|
||||
// Run standalone: `node bin/agent-vm.dispatch.test.js` (no test
|
||||
// harness / deps — matches the repo convention of sanity-checking the
|
||||
// launcher with plain `node`/`node --check`; there is no Node test
|
||||
// runner or root package.json in this repo).
|
||||
//
|
||||
// It must stay in lockstep with the real launcher: it extracts the
|
||||
// live PLATFORM_PACKAGES object out of agent-vm.js (rather than
|
||||
// hard-coding a copy) so a future edit to the mapping that forgets
|
||||
// arm64 — or renames the package — fails here instead of silently
|
||||
// shipping a launcher that falls through to "unsupported platform"
|
||||
// on arm64 hardware.
|
||||
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs");
|
||||
const vm = require("node:vm");
|
||||
|
||||
const launcherPath = path.join(__dirname, "agent-vm.js");
|
||||
const src = fs.readFileSync(launcherPath, "utf8");
|
||||
|
||||
// Pull the `PLATFORM_PACKAGES = { ... };` object-literal out of the
|
||||
// launcher source and evaluate just that literal in an isolated VM
|
||||
// context. We deliberately do NOT `require()` the launcher: it runs
|
||||
// its dispatch + process.exit() at module load, so requiring it would
|
||||
// terminate this test process.
|
||||
const m = src.match(/const\s+PLATFORM_PACKAGES\s*=\s*(\{[\s\S]*?\});/);
|
||||
assert.ok(m, "could not locate PLATFORM_PACKAGES object literal in agent-vm.js");
|
||||
const PLATFORM_PACKAGES = vm.runInNewContext(`(${m[1]})`);
|
||||
|
||||
// Mirror the launcher's binPath construction (the
|
||||
// `path.join(dir, "bin", "agent-vm"+ext)` line) so we assert the SAME
|
||||
// layout the launcher actually uses.
|
||||
function binPathFor(pkgDir, platform) {
|
||||
const ext = platform === "win32" ? ".exe" : "";
|
||||
return path.join(pkgDir, "bin", `agent-vm${ext}`);
|
||||
}
|
||||
|
||||
// 1) The new arm64 key must resolve to the arm64 subpackage.
|
||||
assert.strictEqual(
|
||||
PLATFORM_PACKAGES["linux-arm64"],
|
||||
"@wirenboard/agent-vm-linux-arm64",
|
||||
"linux-arm64 must map to @wirenboard/agent-vm-linux-arm64",
|
||||
);
|
||||
|
||||
// 2) x64 must still resolve (guards against an accidental clobber).
|
||||
assert.strictEqual(
|
||||
PLATFORM_PACKAGES["linux-x64"],
|
||||
"@wirenboard/agent-vm-linux-x64",
|
||||
"linux-x64 must map to @wirenboard/agent-vm-linux-x64",
|
||||
);
|
||||
|
||||
// 3) Both linux platforms must produce the identical bin/ layout
|
||||
// (only the package dir differs) — the arm64 subpackage ships its
|
||||
// binary at bin/agent-vm exactly like x64 (see its package.json
|
||||
// `files` list + the bin/.gitkeep placeholder).
|
||||
const x64Bin = binPathFor("/pkg/agent-vm-linux-x64", "linux");
|
||||
const arm64Bin = binPathFor("/pkg/agent-vm-linux-arm64", "linux");
|
||||
assert.strictEqual(path.basename(x64Bin), "agent-vm");
|
||||
assert.strictEqual(path.basename(arm64Bin), "agent-vm");
|
||||
assert.strictEqual(
|
||||
path.relative("/pkg/agent-vm-linux-x64", x64Bin),
|
||||
path.relative("/pkg/agent-vm-linux-arm64", arm64Bin),
|
||||
"arm64 and x64 must use the same bin/ layout",
|
||||
);
|
||||
|
||||
// 4) A genuinely unsupported platform key must be absent so the
|
||||
// launcher hits its "no prebuilt binary" error path cleanly.
|
||||
assert.strictEqual(
|
||||
PLATFORM_PACKAGES["sunos-sparc"],
|
||||
undefined,
|
||||
"unsupported platform keys must be absent (no fall-through entry)",
|
||||
);
|
||||
|
||||
console.log("agent-vm dispatch test: OK (linux-x64, linux-arm64)");
|
||||
|
|
@ -22,7 +22,7 @@ const fs = require("node:fs");
|
|||
|
||||
const PLATFORM_PACKAGES = {
|
||||
"linux-x64": "@wirenboard/agent-vm-linux-x64",
|
||||
// "linux-arm64": "@wirenboard/agent-vm-linux-arm64",
|
||||
"linux-arm64": "@wirenboard/agent-vm-linux-arm64",
|
||||
// "darwin-arm64": "@wirenboard/agent-vm-darwin-arm64",
|
||||
// "darwin-x64": "@wirenboard/agent-vm-darwin-x64",
|
||||
// "win32-x64": "@wirenboard/agent-vm-win32-x64",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@wirenboard/agent-vm-linux-x64": "0.0.0"
|
||||
"@wirenboard/agent-vm-linux-x64": "0.0.0",
|
||||
"@wirenboard/agent-vm-linux-arm64": "0.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue