Skip to content

Commit 5c98e7f

Browse files
committed
fix: cross-platform publish with musl detection and CI corrections
build-binary.js: - Launcher detects musl vs glibc for hyperlight-analysis .node loading using ldd probe, tries platform-specific .node directly - Uses napi-rs generated index.js for js-host-api (has full detection) - Copies all available platform .node files via ALL_TRIPLES loop publish.yml: - musl build: cross-compiles from glibc runner with musl-tools, uses napi build --target x86_64-unknown-linux-musl, skips tests (musl .node can't run on glibc host) - gnu/win32 builds: run tests natively on their platforms - publish-npm: runs on self-hosted runner (needs Rust toolchain), downloads artifacts AFTER setup to avoid symlink clobber - Verifies musl .node files are produced before artifact upload Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent 78b851f commit 5c98e7f

2 files changed

Lines changed: 56 additions & 6 deletions

File tree

.github/workflows/publish.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ env:
2323
jobs:
2424
# Build native addons on each platform and upload as artifacts.
2525
# These are combined in the publish-npm job to create a cross-platform package.
26+
#
27+
# gnu and win32 builds run tests natively on their platform.
28+
# musl is cross-compiled from the glibc runner (can't run tests on glibc host).
2629
build-native:
2730
name: Build (${{ matrix.build }})
2831
strategy:
@@ -33,12 +36,15 @@ jobs:
3336
- build: linux-kvm
3437
os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
3538
hypervisor: kvm
39+
run_tests: true
3640
- build: linux-musl
3741
os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
3842
hypervisor: kvm
43+
run_tests: false # musl .node can't run on glibc host
3944
- build: windows-whp
4045
os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"]
4146
hypervisor: whp
47+
run_tests: true
4248
runs-on: ${{ matrix.os }}
4349
steps:
4450
- uses: actions/checkout@v6
@@ -56,18 +62,34 @@ jobs:
5662
- name: Setup
5763
run: just setup
5864

59-
- name: Install musl tools
65+
- name: Install musl tools and rebuild for musl target
6066
if: matrix.build == 'linux-musl'
6167
run: |
6268
sudo apt-get update && sudo apt-get install -y musl-tools
6369
rustup target add x86_64-unknown-linux-musl
6470
71+
# Rebuild hyperlight-js NAPI addon targeting musl
72+
hl_dir=$(just resolve-hyperlight-dir)
73+
cd "${hl_dir}/src/js-host-api"
74+
npx napi build --platform --target x86_64-unknown-linux-musl
75+
76+
# Rebuild hyperlight-analysis NAPI addon targeting musl
77+
cd "$GITHUB_WORKSPACE/src/code-validator/guest"
78+
npx napi build --platform --target x86_64-unknown-linux-musl --manifest-path host/Cargo.toml
79+
node -e "require('fs').readdirSync('host').filter(f=>f.endsWith('.node')).forEach(f=>require('fs').copyFileSync('host/'+f,f))"
80+
81+
# Verify musl .node files were actually produced
82+
ls -la "${hl_dir}/src/js-host-api/"*.linux-x64-musl.node
83+
ls -la "$GITHUB_WORKSPACE/src/code-validator/guest/"*linux-x64-musl* || ls -la "$GITHUB_WORKSPACE/src/code-validator/guest/host/"*linux-x64-musl*
84+
6585
- name: Build release binary
86+
if: matrix.run_tests
6687
run: node scripts/build-binary.js --release
6788
env:
6889
VERSION: ${{ github.event.release.tag_name || inputs.version }}
6990

7091
- name: Run tests
92+
if: matrix.run_tests
7193
run: just test
7294

7395
# Upload the native .node addons so the publish job can combine them
@@ -82,11 +104,13 @@ jobs:
82104
if-no-files-found: error
83105
retention-days: 1
84106

85-
# Combine native addons from all platforms and publish a single npm package
107+
# Combine native addons from all platforms and publish a single npm package.
108+
# Runs on a self-hosted Linux runner (not ubuntu-latest) because just setup
109+
# needs to build the Rust runtime which requires hyperlight toolchain.
86110
publish-npm:
87111
name: Publish to npmjs.org
88112
needs: [build-native]
89-
runs-on: ubuntu-latest
113+
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
90114
steps:
91115
- uses: actions/checkout@v6
92116

scripts/build-binary.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,35 @@ Module._load = function(request, parent, isMain) {
432432
return originalLoad.call(this, join(LIB_DIR, 'js-host-api', 'lib.cjs'), parent, isMain);
433433
}
434434
if (request === 'hyperlight-analysis') {
435-
// The hyperlight-analysis index.js already has full napi-rs platform detection.
436-
// It's copied into the node_modules structure, so just load it from there.
437-
return originalLoad.call(this, join(LIB_DIR, 'node_modules', 'hyperlight-analysis', 'index.js'), parent, isMain);
435+
// Load the correct platform-specific .node directly, with musl detection.
436+
// The index.js loader doesn't distinguish musl vs glibc, so we handle it here.
437+
const fs = require('fs');
438+
const hyperlightDir = join(LIB_DIR, 'node_modules', 'hyperlight-analysis');
439+
const platformArch = process.platform + '-' + process.arch;
440+
const candidates = [];
441+
if (platformArch === 'linux-x64') {
442+
// Detect musl vs glibc — try musl first on musl systems, then glibc
443+
let isMusl = false;
444+
try {
445+
const r = require('child_process').spawnSync('ldd', ['--version'],
446+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
447+
isMusl = ((r.stdout || '') + (r.stderr || '')).includes('musl');
448+
} catch {}
449+
if (isMusl) {
450+
candidates.push(join(hyperlightDir, 'hyperlight-analysis.linux-x64-musl.node'));
451+
}
452+
candidates.push(join(hyperlightDir, 'hyperlight-analysis.linux-x64-gnu.node'));
453+
} else if (platformArch === 'win32-x64') {
454+
candidates.push(join(hyperlightDir, 'hyperlight-analysis.win32-x64-msvc.node'));
455+
}
456+
// Fall back to index.js loader
457+
candidates.push(join(hyperlightDir, 'index.js'));
458+
for (const candidate of candidates) {
459+
if (fs.existsSync(candidate)) {
460+
return originalLoad.call(this, candidate, parent, isMain);
461+
}
462+
}
463+
return originalLoad.apply(this, arguments);
438464
}
439465
return originalLoad.apply(this, arguments);
440466
};

0 commit comments

Comments
 (0)