Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
db0acb2
refactor(dstack-mr): extract TDX lite OS check as a pure function
Leechael Nov 10, 2026
cdc3087
feat: add wasm npm package for TDX lite OS verification
Leechael Nov 10, 2026
888300e
ci: add Node, Bun, Electron, and browser matrix for verifier wasm
Leechael Nov 10, 2026
97356c4
ci: fix Electron sandbox and Playwright ESM resolution
Leechael Nov 10, 2026
25cbc50
docs(verifier-wasm): write usage README for JS/TS integrators
Leechael Nov 10, 2026
5ad07ff
ci: add npm trusted-publishing workflow for verifier-wasm
Leechael Nov 10, 2026
472ea4f
fix: remap host paths so the verifier wasm is reproducible
Leechael Nov 10, 2026
b54412a
fix: remap rust-src paths to the virtual rustc prefix
Leechael Nov 10, 2026
08bd98c
build: pin wasm compilation to a linux/amd64 rust image
Leechael Nov 10, 2026
1117600
ci: compare pinned-container wasm on arm64 host via qemu amd64
Leechael Nov 10, 2026
69554e6
fix: ignore repo rust-toolchain overlay inside the wasm container
Leechael Nov 10, 2026
05d3322
ci: retry qemu-user rustc with RUST_MIN_STACK=16MiB
Leechael Nov 10, 2026
6452f5e
ci: drop qemu-user amd64 emulation; rustc 1.92 SIGSEGVs
Leechael Nov 10, 2026
e5f0e3f
chore: version the wasm npm package as 0.1.0-beta.0
Leechael Nov 10, 2026
437b6a5
chore: ship Apache-2.0 LICENSE in the wasm npm package
Leechael Nov 10, 2026
ae9a158
fix: return osImageHash only on success and drop JS acpi flag
Leechael Nov 10, 2026
0192c42
ci: pin verifier-wasm actions by SHA and limit tag triggers
Leechael Nov 10, 2026
0dfbb67
ci: pin verifier-wasm browser jobs to ubuntu-24.04
Leechael Nov 11, 2026
07acd87
dstack-mr: tidy verify_tdx_lite_os extraction
kvinwang Nov 12, 2026
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
141 changes: 141 additions & 0 deletions .github/workflows/verifier-wasm-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# SPDX-FileCopyrightText: © 2026 Phala Network <dstack@phala.network>
#
# SPDX-License-Identifier: Apache-2.0

name: Publish TDX lite verifier wasm to npm
on:
push:
tags: ['verifier-wasm-v*']
workflow_dispatch:
inputs:
npm_tag:
description: 'npm dist-tag (beta, latest)'
required: true
default: 'beta'
type: choice
options:
- beta
- latest

permissions:
id-token: write
contents: write

jobs:
publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: sdk/verifier-wasm
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5

- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'

- name: Upgrade npm for trusted publishers support
run: |
npm install -g npm@11.21.1
echo "npm: $(npm --version)"

- name: Verify OIDC token availability
run: |
if [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL}" ] && [ -n "${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" ]; then
echo "OIDC token available"
else
echo "OIDC token NOT available"
echo "Check workflow permissions include 'id-token: write'"
exit 1
fi

- name: Verify repository configuration
run: |
echo "Checking repository consistency..."
GIT_REPO=$(git remote get-url origin | sed 's/.*github.com[/:]//; s/.git$//')
PKG_REPO=$(node -e "console.log(require('./package.json').repository?.url || '')" | sed 's|https://github.com/||; s|git+||; s|.git$||')
echo "Git remote: $GIT_REPO"
echo "package.json: $PKG_REPO"
if [ "$GIT_REPO" != "$PKG_REPO" ]; then
echo "Repository mismatch!"
echo "This will cause 422 error during publish"
exit 1
fi
echo "Repositories match"

- name: Build wasm package
working-directory: .
env:
REPRO_CHECK: '1'
run: bash sdk/verifier-wasm/scripts/build-in-container.sh

- name: Print wasm sha256
working-directory: .
run: |
python3 - <<'PY'
import hashlib, pathlib, re, base64
js = pathlib.Path('sdk/verifier-wasm/src/wasm-bytes.js')
text = js.read_text()
b64 = re.search(r"wasmBase64 = '([^']+)'", text).group(1)
wasm = base64.b64decode(b64)
print(f"wasm sha256={hashlib.sha256(wasm).hexdigest()}")
print(f"wasm-bytes.js sha256={hashlib.sha256(text.encode()).hexdigest()}")
PY

- name: Run Node tests
run: node test/run-cases.mjs

- name: Determine version and npm dist-tag
id: tag
run: |
PKG_VERSION=$(node -e "console.log(require('./package.json').version)")
PRERELEASE=false
if echo "$PKG_VERSION" | grep -qiE '(beta|alpha|rc|preview)'; then
PRERELEASE=true
fi

if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="$PKG_VERSION"
REQUESTED="${{ github.event.inputs.npm_tag }}"
if [ "$PRERELEASE" = true ] && [ "$REQUESTED" = "latest" ]; then
echo "::error::prerelease $PKG_VERSION cannot be published with dist-tag latest"
exit 1
fi
echo "tag=$REQUESTED" >> "$GITHUB_OUTPUT"
else
TAG_VERSION="${GITHUB_REF_NAME#verifier-wasm-v}"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)"
exit 1
fi
VERSION="$TAG_VERSION"
if [ "$PRERELEASE" = true ]; then
echo "tag=beta" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
fi
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Publish to npm
run: |
NPM_TAG="${{ steps.tag.outputs.tag }}"
echo "Publishing with dist-tag: $NPM_TAG"
npm publish --access public --provenance --tag "$NPM_TAG"

- name: GitHub Release
if: github.event_name == 'push'
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
name: "verifier-wasm v${{ steps.tag.outputs.version }}"
body: |
## npm Package

**Package**: `@phala/dstack-verifier-wasm@${{ steps.tag.outputs.version }}`

**Install**: `npm install @phala/dstack-verifier-wasm@${{ steps.tag.outputs.version }}`

**Dist-tag**: `${{ steps.tag.outputs.tag }}`

**Registry**: https://www.npmjs.com/package/@phala/dstack-verifier-wasm/v/${{ steps.tag.outputs.version }}
208 changes: 208 additions & 0 deletions .github/workflows/verifier-wasm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# SPDX-FileCopyrightText: © 2026 Phala Network <dstack@phala.network>
#
# SPDX-License-Identifier: Apache-2.0

name: TDX lite verifier wasm

on:
push:
branches: [ next, 'release/**' ]
tags: ['verifier-wasm-v*']
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
branches: [ next, 'release/**' ]
workflow_dispatch:
inputs:
runtimes:
description: Run Electron and browser jobs
type: boolean
default: true

permissions:
contents: read

jobs:
changes:
runs-on: ubuntu-latest
outputs:
relevant: ${{ steps.changes.outputs.relevant }}
runtimes: ${{ steps.changes.outputs.runtimes }}
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
fetch-depth: 0

- name: Detect relevant changes
id: changes
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
BEFORE_SHA: ${{ github.event.before }}
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
HAS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'verifier-wasm-runtimes') }}
DISPATCH_RUNTIMES: ${{ github.event_name == 'workflow_dispatch' && inputs.runtimes }}
run: |
relevant=false
if [ "$EVENT_NAME" = "workflow_dispatch" ] || [[ "$REF" == refs/tags/* ]]; then
relevant=true
echo "dispatch or tag: running"
else
if [ -n "$BASE_SHA" ]; then
changed=$(git diff --name-only "$BASE_SHA...HEAD")
elif [ -n "$BEFORE_SHA" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then
changed=$(git diff --name-only "$BEFORE_SHA...HEAD")
else
changed=$(git diff --name-only HEAD~1...HEAD)
fi
echo "$changed"
if echo "$changed" | grep -qE '^(sdk/verifier-wasm/|dstack/crates/dstack-verifier-wasm/|dstack/dstack-mr/|dstack/crates/qemu-acpi/|dstack/dstack-types/|dstack/cc-eventlog/|dstack/Cargo.lock|\.github/workflows/verifier-wasm\.yml)'; then
relevant=true
else
echo "nothing this job covers changed"
fi
fi

runtimes=false
if [ "$relevant" = true ]; then
if [ "$DISPATCH_RUNTIMES" = "true" ]; then
runtimes=true
elif [ "$EVENT_NAME" = "push" ] && { [ "$REF" = "refs/heads/next" ] || [[ "$REF" == refs/tags/* ]]; }; then
runtimes=true
elif [ "$HAS_LABEL" = "true" ]; then
runtimes=true
fi
fi

echo "relevant=$relevant" >> "$GITHUB_OUTPUT"
echo "runtimes=$runtimes" >> "$GITHUB_OUTPUT"
echo "relevant=$relevant runtimes=$runtimes"

build:
needs: changes
if: needs.changes.outputs.relevant == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5

- name: Build wasm in pinned container
env:
REPRO_CHECK: '1'
run: bash sdk/verifier-wasm/scripts/build-in-container.sh

- name: Check wasm imports
run: |
node -e "
const { readFileSync } = require('node:fs');
const js = readFileSync('sdk/verifier-wasm/src/wasm-bytes.js', 'utf8');
const m = js.match(/wasmBase64 = '([^']+)'/);
if (!m) { console.error('no wasmBase64'); process.exit(1); }
const wasm = Buffer.from(m[1], 'base64');
const imports = WebAssembly.Module.imports(new WebAssembly.Module(wasm));
if (imports.length !== 0) {
console.error(imports);
process.exit(1);
}
console.log('imports: none raw=' + wasm.length);
"

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: verifier-wasm-bytes
path: sdk/verifier-wasm/src/wasm-bytes.js
if-no-files-found: error

node:
needs: [changes, build]
if: needs.changes.outputs.relevant == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: ['20.19.0', '22', '24']
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: verifier-wasm-bytes
path: sdk/verifier-wasm/src
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: ${{ matrix.node }}
- name: Run cases
working-directory: sdk/verifier-wasm
run: node test/run-cases.mjs

bun:
needs: [changes, build]
if: needs.changes.outputs.relevant == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: verifier-wasm-bytes
path: sdk/verifier-wasm/src
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: latest
- name: Run cases
working-directory: sdk/verifier-wasm
run: bun test/run-cases.mjs

electron:
needs: [changes, build]
if: needs.changes.outputs.relevant == 'true' && needs.changes.outputs.runtimes == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
electron: ['31', 'latest']
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: verifier-wasm-bytes
path: sdk/verifier-wasm/src
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: '22'
- name: Install Electron
run: |
mkdir -p "$RUNNER_TEMP/electron"
cd "$RUNNER_TEMP/electron"
npm init -y >/dev/null
npm install "electron@${{ matrix.electron }}"
echo "ELECTRON_BIN=$RUNNER_TEMP/electron/node_modules/.bin/electron" >> "$GITHUB_ENV"
ELECTRON_RUN_AS_NODE=1 "$RUNNER_TEMP/electron/node_modules/.bin/electron" -e 'console.log(process.versions.electron)'
- name: Run cases as Node
working-directory: sdk/verifier-wasm
run: ELECTRON_RUN_AS_NODE=1 "$ELECTRON_BIN" test/run-cases.mjs
- name: Install xvfb
run: sudo apt-get update && sudo apt-get install -y xvfb
- name: Run cases in Electron main
working-directory: sdk/verifier-wasm
run: xvfb-run -a "$ELECTRON_BIN" --no-sandbox test/electron-main.mjs

browser:
needs: [changes, build]
if: needs.changes.outputs.relevant == 'true' && needs.changes.outputs.runtimes == 'true'
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: verifier-wasm-bytes
path: sdk/verifier-wasm/src
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: '20'
- name: Install Playwright and run cases
working-directory: sdk/verifier-wasm
run: |
npm install --no-save --no-package-lock playwright@1.65.0
npx playwright install --with-deps ${{ matrix.browser }}
node test/browser/playwright.mjs ${{ matrix.browser }}
17 changes: 16 additions & 1 deletion dstack/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dstack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ members = [
"crates/mock-attestation",
"crates/qemu-acpi",
"crates/pki-fetch",
"crates/dstack-verifier-wasm",
]
# Vendored third-party crates are path dependencies but deliberately not members:
# `--all-features` applies to members, and ktls declares its `ring` and
Expand Down
Loading
Loading