From 60e3a6b51dec5d089cb8a6e30ed8c1a2056e5463 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 11:58:57 -0600 Subject: [PATCH 01/15] docs(amdsev): add control channel startup steps --- misc/AMDSEV/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/misc/AMDSEV/README.md b/misc/AMDSEV/README.md index 1e17bf731..a8a2b4c25 100644 --- a/misc/AMDSEV/README.md +++ b/misc/AMDSEV/README.md @@ -155,6 +155,30 @@ The script: - Forwards RPC port 5050 to host port 15051 - Outputs serial log to a temp file and follows it +### Start Katana via Control Channel + +To start Katana manually over the control channel: + +```sh +# 1) Boot VM without auto-starting Katana +sudo ./misc/AMDSEV/start-vm.sh --no-start + +# 2) Use the control socket printed by start-vm.sh (example path below) +CONTROL_SOCKET=/tmp/katana-tee-vm-control.12345.sock + +# 3) Start Katana with comma-separated CLI args +printf 'start --http.addr,0.0.0.0,--http.port,5050,--tee.provider,sev-snp\n' \ + | socat - UNIX-CONNECT:"$CONTROL_SOCKET" + +# 4) Check launcher status +printf 'status\n' | socat - UNIX-CONNECT:"$CONTROL_SOCKET" +``` + +Control responses: +- `ok started pid=...` means Katana was launched. +- `running pid=...` means Katana is still running. +- `stopped exit=...` means Katana is not running. + ### Launch Measurement Verification To verify a TEE VM's integrity, compute the expected launch measurement using `snp-digest`: From 7095046f465941cf2edc9396b411af048e39277b Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 12:05:58 -0600 Subject: [PATCH 02/15] docs(amdsev): clarify control socket channel --- misc/AMDSEV/README.md | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/misc/AMDSEV/README.md b/misc/AMDSEV/README.md index a8a2b4c25..1e17bf731 100644 --- a/misc/AMDSEV/README.md +++ b/misc/AMDSEV/README.md @@ -155,30 +155,6 @@ The script: - Forwards RPC port 5050 to host port 15051 - Outputs serial log to a temp file and follows it -### Start Katana via Control Channel - -To start Katana manually over the control channel: - -```sh -# 1) Boot VM without auto-starting Katana -sudo ./misc/AMDSEV/start-vm.sh --no-start - -# 2) Use the control socket printed by start-vm.sh (example path below) -CONTROL_SOCKET=/tmp/katana-tee-vm-control.12345.sock - -# 3) Start Katana with comma-separated CLI args -printf 'start --http.addr,0.0.0.0,--http.port,5050,--tee.provider,sev-snp\n' \ - | socat - UNIX-CONNECT:"$CONTROL_SOCKET" - -# 4) Check launcher status -printf 'status\n' | socat - UNIX-CONNECT:"$CONTROL_SOCKET" -``` - -Control responses: -- `ok started pid=...` means Katana was launched. -- `running pid=...` means Katana is still running. -- `stopped exit=...` means Katana is not running. - ### Launch Measurement Verification To verify a TEE VM's integrity, compute the expected launch measurement using `snp-digest`: From d589cef13e15da0fff26ce57adf264d524813e25 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 10:58:36 -0600 Subject: [PATCH 03/15] Add isolated AMDSEV initrd validation script --- misc/AMDSEV/README.md | 16 ++ misc/AMDSEV/test-initrd.sh | 335 +++++++++++++++++++++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100644 misc/AMDSEV/test-initrd.sh diff --git a/misc/AMDSEV/README.md b/misc/AMDSEV/README.md index 1e17bf731..324f18789 100644 --- a/misc/AMDSEV/README.md +++ b/misc/AMDSEV/README.md @@ -39,6 +39,7 @@ If `--katana` is not provided, `build.sh` prompts for confirmation (`y/N`) befor | `build-ovmf.sh` | Builds OVMF firmware from AMD's fork with SEV-SNP support | | `build-kernel.sh` | Downloads and extracts Ubuntu kernel (`vmlinuz`) | | `build-initrd.sh` | Creates minimal initrd with busybox, SEV-SNP modules, and katana | +| `test-initrd.sh` | Runs isolated initrd validation (archive checks + plain QEMU boot smoke) | | `build-config` | Pinned versions and checksums for reproducible builds | | `start-vm.sh` | Starts a TEE VM with SEV-SNP and launches Katana asynchronously | @@ -155,6 +156,21 @@ The script: - Forwards RPC port 5050 to host port 15051 - Outputs serial log to a temp file and follows it +## Isolated Initrd Testing + +Use `test-initrd.sh` for focused initrd validation without the full SEV-SNP launch path: + +```sh +# Run static archive/content checks and plain-QEMU boot smoke test +./misc/AMDSEV/test-initrd.sh + +# Only check initrd archive contents +./misc/AMDSEV/test-initrd.sh --static-only + +# Only run plain-QEMU boot smoke test +./misc/AMDSEV/test-initrd.sh --boot-only +``` + ### Launch Measurement Verification To verify a TEE VM's integrity, compute the expected launch measurement using `snp-digest`: diff --git a/misc/AMDSEV/test-initrd.sh b/misc/AMDSEV/test-initrd.sh new file mode 100644 index 000000000..d26b6452b --- /dev/null +++ b/misc/AMDSEV/test-initrd.sh @@ -0,0 +1,335 @@ +#!/bin/bash +# ============================================================================== +# TEST-INITRD.SH - Isolated initrd validation for AMDSEV +# ============================================================================== +# +# Runs focused checks for initrd behavior without requiring the full SEV-SNP +# launch path: +# 1) Static archive/content checks (no VM boot) +# 2) Plain-QEMU boot smoke test with RPC health check (no OVMF/SEV) +# +# Usage: +# ./test-initrd.sh [OPTIONS] +# +# Options: +# --output-dir DIR Boot artifacts directory (default: ./output/qemu) +# --static-only Run only static initrd checks +# --boot-only Run only boot smoke test +# --host-rpc-port PORT Host port for forwarded Katana RPC (default: 15052) +# --vm-rpc-port PORT Guest Katana RPC port (default: 5050) +# --timeout SEC Boot wait timeout in seconds (default: 90) +# -h, --help Show usage +# +# Environment: +# QEMU_BIN Optional path to qemu-system-x86_64 +# TEST_DISK_SIZE Ephemeral test disk size (default: 1G) +# ============================================================================== + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUTPUT_DIR="${SCRIPT_DIR}/output/qemu" +INITRD_FILE="" +KERNEL_FILE="" +RUN_STATIC=1 +RUN_BOOT=1 +HOST_RPC_PORT=15052 +VM_RPC_PORT=5050 +BOOT_TIMEOUT=90 +TEST_DISK_SIZE="${TEST_DISK_SIZE:-1G}" + +TEMP_DIR="$(mktemp -d /tmp/katana-amdsev-initrd-test.XXXXXX)" +EXTRACT_DIR="${TEMP_DIR}/extract" +SERIAL_LOG="${TEMP_DIR}/serial.log" +DISK_IMG="${TEMP_DIR}/test-disk.img" +QEMU_PID="" + +usage() { + cat <&2 +} + +die() { + echo "[test-initrd] ERROR: $*" >&2 + exit 1 +} + +require_tool() { + local tool="$1" + command -v "$tool" >/dev/null 2>&1 || die "Required tool not found: $tool" +} + +cleanup() { + local exit_code=$? + + if [ -n "$QEMU_PID" ] && kill -0 "$QEMU_PID" 2>/dev/null; then + log "Stopping QEMU (PID $QEMU_PID)..." + kill "$QEMU_PID" 2>/dev/null || true + + for _ in $(seq 1 10); do + if ! kill -0 "$QEMU_PID" 2>/dev/null; then + break + fi + sleep 0.5 + done + + if kill -0 "$QEMU_PID" 2>/dev/null; then + warn "QEMU still running, force killing" + kill -9 "$QEMU_PID" 2>/dev/null || true + fi + + wait "$QEMU_PID" 2>/dev/null || true + fi + + rm -rf "$TEMP_DIR" + exit "$exit_code" +} +trap cleanup EXIT INT TERM + +while [[ $# -gt 0 ]]; do + case "$1" in + --output-dir) + OUTPUT_DIR="${2:?Missing value for --output-dir}" + shift 2 + ;; + --static-only) + RUN_STATIC=1 + RUN_BOOT=0 + shift + ;; + --boot-only) + RUN_STATIC=0 + RUN_BOOT=1 + shift + ;; + --host-rpc-port) + HOST_RPC_PORT="${2:?Missing value for --host-rpc-port}" + shift 2 + ;; + --vm-rpc-port) + VM_RPC_PORT="${2:?Missing value for --vm-rpc-port}" + shift 2 + ;; + --timeout) + BOOT_TIMEOUT="${2:?Missing value for --timeout}" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + die "Unknown argument: $1" + ;; + esac +done + +INITRD_FILE="${OUTPUT_DIR}/initrd.img" +KERNEL_FILE="${OUTPUT_DIR}/vmlinuz" + +assert_extract_path() { + local rel_path="$1" + if [ ! -e "${EXTRACT_DIR}/${rel_path}" ]; then + die "Expected initrd path missing: ${rel_path}" + fi +} + +assert_init_contains() { + local pattern="$1" + if ! grep -Fq -- "$pattern" "${EXTRACT_DIR}/init"; then + die "Expected pattern missing in init script: ${pattern}" + fi +} + +run_static_checks() { + log "Running static initrd checks" + + require_tool gzip + require_tool cpio + require_tool grep + + [ -f "$INITRD_FILE" ] || die "Initrd not found: $INITRD_FILE" + + if ! gzip -t "$INITRD_FILE" 2>/dev/null; then + die "Initrd is not valid gzip: $INITRD_FILE" + fi + + mkdir -p "$EXTRACT_DIR" + ( + cd "$EXTRACT_DIR" + gzip -dc "$INITRD_FILE" | cpio -id --quiet + ) + + REQUIRED_PATHS=( + init + bin/busybox + bin/katana + etc/passwd + etc/group + bin/sh + bin/mount + bin/umount + bin/ip + bin/insmod + bin/poweroff + bin/sync + ) + + for path in "${REQUIRED_PATHS[@]}"; do + assert_extract_path "$path" + done + + [ -x "${EXTRACT_DIR}/init" ] || die "Init script is not executable" + [ -x "${EXTRACT_DIR}/bin/katana" ] || die "Katana binary in initrd is not executable" + + assert_init_contains "trap shutdown_handler TERM INT" + assert_init_contains "poweroff -f" + assert_init_contains "exec 0/dev/null 2>&1; then + command -v qemu-system-x86_64 + return 0 + fi + + if [ -x "${OUTPUT_DIR}/bin/qemu-system-x86_64" ]; then + echo "${OUTPUT_DIR}/bin/qemu-system-x86_64" + return 0 + fi + + return 1 +} + +run_boot_smoke_test() { + local qemu_bin + local response="" + local ready=0 + + log "Running plain-QEMU boot smoke test" + + [ -f "$KERNEL_FILE" ] || die "Kernel not found: $KERNEL_FILE" + [ -f "$INITRD_FILE" ] || die "Initrd not found: $INITRD_FILE" + + qemu_bin="$(resolve_qemu_bin)" || die "qemu-system-x86_64 not found (set QEMU_BIN if needed)" + + require_tool curl + require_tool mkfs.ext4 + require_tool truncate + + truncate -s "$TEST_DISK_SIZE" "$DISK_IMG" + mkfs.ext4 -q -F "$DISK_IMG" + + KVM_OPTS=() + if [ -r /dev/kvm ] && [ -w /dev/kvm ]; then + KVM_OPTS=(-enable-kvm -cpu host) + log "Using KVM acceleration" + else + warn "/dev/kvm not accessible; using software emulation" + KVM_OPTS=(-cpu max) + fi + + "$qemu_bin" \ + "${KVM_OPTS[@]}" \ + -m 512M \ + -smp 1 \ + -nographic \ + -serial "file:$SERIAL_LOG" \ + -kernel "$KERNEL_FILE" \ + -initrd "$INITRD_FILE" \ + -append "console=ttyS0 katana.args=--http.addr,0.0.0.0,--http.port,${VM_RPC_PORT},--tee.provider,sev-snp" \ + -device virtio-scsi-pci,id=scsi0 \ + -drive "file=${DISK_IMG},format=raw,if=none,id=disk0,cache=none" \ + -device scsi-hd,drive=disk0,bus=scsi0.0 \ + -netdev "user,id=net0,hostfwd=tcp::${HOST_RPC_PORT}-:${VM_RPC_PORT}" \ + -device virtio-net-pci,netdev=net0 \ + & + + QEMU_PID=$! + log "QEMU started with PID $QEMU_PID" + + for ((elapsed = 1; elapsed <= BOOT_TIMEOUT; elapsed++)); do + if ! kill -0 "$QEMU_PID" 2>/dev/null; then + warn "QEMU exited before RPC became ready" + if [ -f "$SERIAL_LOG" ]; then + echo "=== Serial output ===" >&2 + tail -n 200 "$SERIAL_LOG" >&2 || true + fi + die "Boot smoke test failed" + fi + + response="$(curl -s --max-time 2 -X POST \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"starknet_chainId","id":1}' \ + "http://127.0.0.1:${HOST_RPC_PORT}" || true)" + + if echo "$response" | grep -q '"result"'; then + ready=1 + break + fi + + if (( elapsed % 5 == 0 )); then + log "Waiting for Katana RPC... (${elapsed}s/${BOOT_TIMEOUT}s)" + fi + sleep 1 + done + + if [ "$ready" -ne 1 ]; then + warn "Timed out waiting for Katana RPC" + if [ -f "$SERIAL_LOG" ]; then + echo "=== Serial output ===" >&2 + tail -n 200 "$SERIAL_LOG" >&2 || true + fi + die "Boot smoke test timed out" + fi + + log "RPC check passed: $response" + log "Boot smoke test passed" +} + +log "Output directory: $OUTPUT_DIR" +log "Modes: static=$RUN_STATIC boot=$RUN_BOOT" + +if [ "$RUN_STATIC" -eq 1 ]; then + run_static_checks +fi + +if [ "$RUN_BOOT" -eq 1 ]; then + run_boot_smoke_test +fi + +log "All requested initrd checks passed" From 118c891b67a26728787e3aa0849d38a514a66cee Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 10:59:14 -0600 Subject: [PATCH 04/15] Mark test-initrd.sh as executable --- misc/AMDSEV/test-initrd.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 misc/AMDSEV/test-initrd.sh diff --git a/misc/AMDSEV/test-initrd.sh b/misc/AMDSEV/test-initrd.sh old mode 100644 new mode 100755 From da8c7a42d868290034271440510dd5bfd3cc2eca Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 11:25:23 -0600 Subject: [PATCH 05/15] Add CI workflow for isolated AMDSEV initrd tests --- .github/workflows/amdsev-initrd-test.yml | 79 ++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/workflows/amdsev-initrd-test.yml diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml new file mode 100644 index 000000000..addb88f55 --- /dev/null +++ b/.github/workflows/amdsev-initrd-test.yml @@ -0,0 +1,79 @@ +name: amdsev-initrd-test + +on: + push: + branches: + - main + paths: + - "misc/AMDSEV/**" + - "scripts/build-musl.sh" + - ".github/workflows/amdsev-initrd-test.yml" + + pull_request: + types: [opened, synchronize, ready_for_review] + paths: + - "misc/AMDSEV/**" + - "scripts/build-musl.sh" + - ".github/workflows/amdsev-initrd-test.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + amdsev-initrd-test: + runs-on: ubuntu-latest + timeout-minutes: 90 + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false) + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + qemu-system-x86 \ + cpio \ + zstd \ + e2fsprogs \ + curl \ + musl-tools \ + clang + + - uses: Swatinem/rust-cache@v2 + with: + key: ci-${{ github.job }} + shared-key: katana-ci-cache-musl + + - name: Build required VM components + run: | + set -euo pipefail + source misc/AMDSEV/build-config + export SOURCE_DATE_EPOCH="$(git log -1 --format=%ct)" + + ./scripts/build-musl.sh + KATANA_BINARY="./target/x86_64-unknown-linux-musl/performance/katana" + + ./misc/AMDSEV/build-kernel.sh ./misc/AMDSEV/output/qemu + ./misc/AMDSEV/build-initrd.sh "$KATANA_BINARY" ./misc/AMDSEV/output/qemu/initrd.img "$KERNEL_VERSION" + + cp "$KATANA_BINARY" ./misc/AMDSEV/output/qemu/katana + + - name: Run isolated initrd tests + run: | + ./misc/AMDSEV/test-initrd.sh --output-dir ./misc/AMDSEV/output/qemu --timeout 300 + + - name: Upload AMDSEV build output on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: amdsev-initrd-output-${{ github.run_id }} + if-no-files-found: ignore + path: | + misc/AMDSEV/output/qemu From 2e616f4460b1b76f77cdd353af649ce605fa8042 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 11:34:03 -0600 Subject: [PATCH 06/15] Remove static checks from AMDSEV initrd test --- misc/AMDSEV/README.md | 13 ++--- misc/AMDSEV/test-initrd.sh | 104 ++----------------------------------- 2 files changed, 8 insertions(+), 109 deletions(-) diff --git a/misc/AMDSEV/README.md b/misc/AMDSEV/README.md index 324f18789..4234ba875 100644 --- a/misc/AMDSEV/README.md +++ b/misc/AMDSEV/README.md @@ -39,7 +39,7 @@ If `--katana` is not provided, `build.sh` prompts for confirmation (`y/N`) befor | `build-ovmf.sh` | Builds OVMF firmware from AMD's fork with SEV-SNP support | | `build-kernel.sh` | Downloads and extracts Ubuntu kernel (`vmlinuz`) | | `build-initrd.sh` | Creates minimal initrd with busybox, SEV-SNP modules, and katana | -| `test-initrd.sh` | Runs isolated initrd validation (archive checks + plain QEMU boot smoke) | +| `test-initrd.sh` | Runs isolated initrd boot smoke test in plain QEMU | | `build-config` | Pinned versions and checksums for reproducible builds | | `start-vm.sh` | Starts a TEE VM with SEV-SNP and launches Katana asynchronously | @@ -158,17 +158,14 @@ The script: ## Isolated Initrd Testing -Use `test-initrd.sh` for focused initrd validation without the full SEV-SNP launch path: +Use `test-initrd.sh` for focused initrd boot validation without the full SEV-SNP launch path: ```sh -# Run static archive/content checks and plain-QEMU boot smoke test +# Run plain-QEMU boot smoke test ./misc/AMDSEV/test-initrd.sh -# Only check initrd archive contents -./misc/AMDSEV/test-initrd.sh --static-only - -# Only run plain-QEMU boot smoke test -./misc/AMDSEV/test-initrd.sh --boot-only +# Custom timeout/output directory +./misc/AMDSEV/test-initrd.sh --output-dir ./misc/AMDSEV/output/qemu --timeout 300 ``` ### Launch Measurement Verification diff --git a/misc/AMDSEV/test-initrd.sh b/misc/AMDSEV/test-initrd.sh index d26b6452b..23709e6f0 100755 --- a/misc/AMDSEV/test-initrd.sh +++ b/misc/AMDSEV/test-initrd.sh @@ -3,18 +3,14 @@ # TEST-INITRD.SH - Isolated initrd validation for AMDSEV # ============================================================================== # -# Runs focused checks for initrd behavior without requiring the full SEV-SNP -# launch path: -# 1) Static archive/content checks (no VM boot) -# 2) Plain-QEMU boot smoke test with RPC health check (no OVMF/SEV) +# Runs a focused initrd boot smoke test without requiring the full SEV-SNP +# launch path. Uses plain QEMU (no OVMF/SEV) and validates Katana RPC readiness. # # Usage: # ./test-initrd.sh [OPTIONS] # # Options: # --output-dir DIR Boot artifacts directory (default: ./output/qemu) -# --static-only Run only static initrd checks -# --boot-only Run only boot smoke test # --host-rpc-port PORT Host port for forwarded Katana RPC (default: 15052) # --vm-rpc-port PORT Guest Katana RPC port (default: 5050) # --timeout SEC Boot wait timeout in seconds (default: 90) @@ -31,15 +27,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" OUTPUT_DIR="${SCRIPT_DIR}/output/qemu" INITRD_FILE="" KERNEL_FILE="" -RUN_STATIC=1 -RUN_BOOT=1 HOST_RPC_PORT=15052 VM_RPC_PORT=5050 BOOT_TIMEOUT=90 TEST_DISK_SIZE="${TEST_DISK_SIZE:-1G}" TEMP_DIR="$(mktemp -d /tmp/katana-amdsev-initrd-test.XXXXXX)" -EXTRACT_DIR="${TEMP_DIR}/extract" SERIAL_LOG="${TEMP_DIR}/serial.log" DISK_IMG="${TEMP_DIR}/test-disk.img" QEMU_PID="" @@ -50,8 +43,6 @@ Usage: $0 [OPTIONS] Options: --output-dir DIR Boot artifacts directory (default: ./output/qemu) - --static-only Run only static initrd checks - --boot-only Run only boot smoke test --host-rpc-port PORT Host port for forwarded Katana RPC (default: 15052) --vm-rpc-port PORT Guest Katana RPC port (default: 5050) --timeout SEC Boot wait timeout in seconds (default: 90) @@ -110,16 +101,6 @@ while [[ $# -gt 0 ]]; do OUTPUT_DIR="${2:?Missing value for --output-dir}" shift 2 ;; - --static-only) - RUN_STATIC=1 - RUN_BOOT=0 - shift - ;; - --boot-only) - RUN_STATIC=0 - RUN_BOOT=1 - shift - ;; --host-rpc-port) HOST_RPC_PORT="${2:?Missing value for --host-rpc-port}" shift 2 @@ -145,77 +126,6 @@ done INITRD_FILE="${OUTPUT_DIR}/initrd.img" KERNEL_FILE="${OUTPUT_DIR}/vmlinuz" -assert_extract_path() { - local rel_path="$1" - if [ ! -e "${EXTRACT_DIR}/${rel_path}" ]; then - die "Expected initrd path missing: ${rel_path}" - fi -} - -assert_init_contains() { - local pattern="$1" - if ! grep -Fq -- "$pattern" "${EXTRACT_DIR}/init"; then - die "Expected pattern missing in init script: ${pattern}" - fi -} - -run_static_checks() { - log "Running static initrd checks" - - require_tool gzip - require_tool cpio - require_tool grep - - [ -f "$INITRD_FILE" ] || die "Initrd not found: $INITRD_FILE" - - if ! gzip -t "$INITRD_FILE" 2>/dev/null; then - die "Initrd is not valid gzip: $INITRD_FILE" - fi - - mkdir -p "$EXTRACT_DIR" - ( - cd "$EXTRACT_DIR" - gzip -dc "$INITRD_FILE" | cpio -id --quiet - ) - - REQUIRED_PATHS=( - init - bin/busybox - bin/katana - etc/passwd - etc/group - bin/sh - bin/mount - bin/umount - bin/ip - bin/insmod - bin/poweroff - bin/sync - ) - - for path in "${REQUIRED_PATHS[@]}"; do - assert_extract_path "$path" - done - - [ -x "${EXTRACT_DIR}/init" ] || die "Init script is not executable" - [ -x "${EXTRACT_DIR}/bin/katana" ] || die "Katana binary in initrd is not executable" - - assert_init_contains "trap shutdown_handler TERM INT" - assert_init_contains "poweroff -f" - assert_init_contains "exec 0 Date: Thu, 26 Feb 2026 11:52:25 -0600 Subject: [PATCH 07/15] Fix AMDSEV CI binary build prerequisites --- .github/workflows/amdsev-initrd-test.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index addb88f55..082495df2 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -28,16 +28,22 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 90 if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false) + container: + image: ghcr.io/dojoengine/katana-dev:latest steps: - uses: actions/checkout@v4 with: submodules: recursive + # Workaround for https://github.com/actions/runner-images/issues/6775 + - run: git config --global --add safe.directory "*" + - name: Install dependencies run: | - sudo apt-get update - sudo apt-get install -y \ + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y \ qemu-system-x86 \ cpio \ zstd \ @@ -51,6 +57,9 @@ jobs: key: ci-${{ github.job }} shared-key: katana-ci-cache-musl + - name: Build contract artifacts + run: make contracts + - name: Build required VM components run: | set -euo pipefail From 18c23ddb723d34bf8381da458a65e6c15850628e Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 11:56:53 -0600 Subject: [PATCH 08/15] Run AMDSEV build step with bash in CI --- .github/workflows/amdsev-initrd-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index 082495df2..831a5e364 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -61,6 +61,7 @@ jobs: run: make contracts - name: Build required VM components + shell: bash run: | set -euo pipefail source misc/AMDSEV/build-config From 6bb8e980463e37ba4c62f1f7ad8d1a0687ae6e72 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 12:31:27 -0600 Subject: [PATCH 09/15] Update initrd smoke test for async control channel --- .github/workflows/amdsev-initrd-test.yml | 1 + misc/AMDSEV/test-initrd.sh | 101 +++++++++++++++++++---- 2 files changed, 88 insertions(+), 14 deletions(-) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index 831a5e364..9afd49f11 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -49,6 +49,7 @@ jobs: zstd \ e2fsprogs \ curl \ + socat \ musl-tools \ clang diff --git a/misc/AMDSEV/test-initrd.sh b/misc/AMDSEV/test-initrd.sh index 23709e6f0..bc25c9b3d 100755 --- a/misc/AMDSEV/test-initrd.sh +++ b/misc/AMDSEV/test-initrd.sh @@ -4,7 +4,8 @@ # ============================================================================== # # Runs a focused initrd boot smoke test without requiring the full SEV-SNP -# launch path. Uses plain QEMU (no OVMF/SEV) and validates Katana RPC readiness. +# launch path. Uses plain QEMU (no OVMF/SEV), starts Katana through the +# async control channel, and validates RPC readiness. # # Usage: # ./test-initrd.sh [OPTIONS] @@ -35,6 +36,7 @@ TEST_DISK_SIZE="${TEST_DISK_SIZE:-1G}" TEMP_DIR="$(mktemp -d /tmp/katana-amdsev-initrd-test.XXXXXX)" SERIAL_LOG="${TEMP_DIR}/serial.log" DISK_IMG="${TEMP_DIR}/test-disk.img" +CONTROL_SOCKET="${TEMP_DIR}/katana-control.sock" QEMU_PID="" usage() { @@ -68,6 +70,80 @@ require_tool() { command -v "$tool" >/dev/null 2>&1 || die "Required tool not found: $tool" } +print_serial_output() { + if [ -f "$SERIAL_LOG" ]; then + echo "=== Serial output ===" >&2 + tail -n 200 "$SERIAL_LOG" >&2 || true + fi +} + +assert_qemu_running() { + local message="$1" + if ! kill -0 "$QEMU_PID" 2>/dev/null; then + warn "QEMU exited unexpectedly" + print_serial_output + die "$message" + fi +} + +send_control_command() { + local cmd="$1" + printf '%s\n' "$cmd" | socat -T 5 - UNIX-CONNECT:"$CONTROL_SOCKET" 2>/dev/null | head -n 1 | tr -d '\r' +} + +wait_for_control_channel() { + local response="" + + for ((elapsed = 1; elapsed <= BOOT_TIMEOUT; elapsed++)); do + assert_qemu_running "Boot smoke test failed" + + if [ -S "$CONTROL_SOCKET" ]; then + response="$(send_control_command status || true)" + case "$response" in + running\ *|stopped\ *) + log "Control channel ready: $response" + return 0 + ;; + esac + fi + + if (( elapsed % 5 == 0 )); then + log "Waiting for control channel... (${elapsed}s/${BOOT_TIMEOUT}s)" + fi + sleep 1 + done + + warn "Timed out waiting for control channel" + print_serial_output + die "Boot smoke test timed out" +} + +start_katana_via_control_channel() { + local start_cmd="start --http.addr,0.0.0.0,--http.port,${VM_RPC_PORT},--tee.provider,sev-snp" + local response="" + + for ((elapsed = 1; elapsed <= BOOT_TIMEOUT; elapsed++)); do + assert_qemu_running "Boot smoke test failed" + + response="$(send_control_command "$start_cmd" || true)" + case "$response" in + ok\ started\ *|err\ already-running\ *) + log "Katana start acknowledged: $response" + return 0 + ;; + esac + + if (( elapsed % 5 == 0 )); then + log "Waiting for Katana start acknowledgement... (${elapsed}s/${BOOT_TIMEOUT}s)" + fi + sleep 1 + done + + warn "Timed out waiting for Katana start acknowledgement" + print_serial_output + die "Boot smoke test timed out" +} + cleanup() { local exit_code=$? @@ -160,6 +236,7 @@ run_boot_smoke_test() { require_tool curl require_tool mkfs.ext4 require_tool truncate + require_tool socat truncate -s "$TEST_DISK_SIZE" "$DISK_IMG" mkfs.ext4 -q -F "$DISK_IMG" @@ -181,7 +258,10 @@ run_boot_smoke_test() { -serial "file:$SERIAL_LOG" \ -kernel "$KERNEL_FILE" \ -initrd "$INITRD_FILE" \ - -append "console=ttyS0 katana.args=--http.addr,0.0.0.0,--http.port,${VM_RPC_PORT},--tee.provider,sev-snp" \ + -append "console=ttyS0" \ + -device virtio-serial-pci,id=virtio-serial0 \ + -chardev "socket,id=katanactl,path=${CONTROL_SOCKET},server=on,wait=off" \ + -device virtserialport,chardev=katanactl,name=org.katana.control.0 \ -device virtio-scsi-pci,id=scsi0 \ -drive "file=${DISK_IMG},format=raw,if=none,id=disk0,cache=none" \ -device scsi-hd,drive=disk0,bus=scsi0.0 \ @@ -192,15 +272,11 @@ run_boot_smoke_test() { QEMU_PID=$! log "QEMU started with PID $QEMU_PID" + wait_for_control_channel + start_katana_via_control_channel + for ((elapsed = 1; elapsed <= BOOT_TIMEOUT; elapsed++)); do - if ! kill -0 "$QEMU_PID" 2>/dev/null; then - warn "QEMU exited before RPC became ready" - if [ -f "$SERIAL_LOG" ]; then - echo "=== Serial output ===" >&2 - tail -n 200 "$SERIAL_LOG" >&2 || true - fi - die "Boot smoke test failed" - fi + assert_qemu_running "Boot smoke test failed" response="$(curl -s --max-time 2 -X POST \ -H "Content-Type: application/json" \ @@ -220,10 +296,7 @@ run_boot_smoke_test() { if [ "$ready" -ne 1 ]; then warn "Timed out waiting for Katana RPC" - if [ -f "$SERIAL_LOG" ]; then - echo "=== Serial output ===" >&2 - tail -n 200 "$SERIAL_LOG" >&2 || true - fi + print_serial_output die "Boot smoke test timed out" fi From e72abaeea1e170782c12205b444ea078ff6b5fcc Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 13:16:27 -0600 Subject: [PATCH 10/15] Install file utility in AMDSEV initrd test workflow --- .github/workflows/amdsev-initrd-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index 9afd49f11..376835ad5 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -51,7 +51,8 @@ jobs: curl \ socat \ musl-tools \ - clang + clang \ + file - uses: Swatinem/rust-cache@v2 with: From 526647d169a9e0b524a91c6f945af32ae892c14b Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 13:51:01 -0600 Subject: [PATCH 11/15] Export AMDSEV build-config vars in CI build step --- .github/workflows/amdsev-initrd-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index 376835ad5..8346854a6 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -66,7 +66,9 @@ jobs: shell: bash run: | set -euo pipefail + set -a source misc/AMDSEV/build-config + set +a export SOURCE_DATE_EPOCH="$(git log -1 --format=%ct)" ./scripts/build-musl.sh From 22f5986698c8021b06523282394b1cf8bb0d18da Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 14:27:16 -0600 Subject: [PATCH 12/15] Fix AMDSEV kernel package fetch in CI --- .github/workflows/amdsev-initrd-test.yml | 9 +++++++++ misc/AMDSEV/build-config | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/amdsev-initrd-test.yml b/.github/workflows/amdsev-initrd-test.yml index 8346854a6..4b39c343d 100644 --- a/.github/workflows/amdsev-initrd-test.yml +++ b/.github/workflows/amdsev-initrd-test.yml @@ -54,6 +54,15 @@ jobs: clang \ file + - name: Add Ubuntu package repo for AMDSEV artifacts + run: | + cat >/etc/apt/sources.list.d/ubuntu-noble.list <<'EOF' + deb [trusted=yes] http://archive.ubuntu.com/ubuntu noble main universe + deb [trusted=yes] http://archive.ubuntu.com/ubuntu noble-updates main universe + deb [trusted=yes] http://security.ubuntu.com/ubuntu noble-security main universe + EOF + apt-get update + - uses: Swatinem/rust-cache@v2 with: key: ci-${{ github.job }} diff --git a/misc/AMDSEV/build-config b/misc/AMDSEV/build-config index feba66845..02e8a918c 100644 --- a/misc/AMDSEV/build-config +++ b/misc/AMDSEV/build-config @@ -11,7 +11,7 @@ OVMF_COMMIT="fbe0805b2091393406952e84724188f8c1941837" # Linux kernel (Ubuntu package) KERNEL_VERSION="6.8.0-90" -KERNEL_PKG_SHA256="19efb319503d92ecfc92a5e8c9ec5546461d88273b375203c3d4ebbd7ae1d61f" +KERNEL_PKG_SHA256="3c1fac8583c9ffee1d38985f6a4c2abaebda6852396ad70d1a8688dcab4ef1fc" # Busybox (Ubuntu package, for initrd) BUSYBOX_PKG_VERSION="1:1.36.1-6ubuntu3.1" From 735a4baebf19e6645869d67c4ab19265f2b3c1f5 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 15:16:06 -0600 Subject: [PATCH 13/15] Restore AMDSEV kernel package checksum pin --- misc/AMDSEV/build-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/AMDSEV/build-config b/misc/AMDSEV/build-config index 02e8a918c..feba66845 100644 --- a/misc/AMDSEV/build-config +++ b/misc/AMDSEV/build-config @@ -11,7 +11,7 @@ OVMF_COMMIT="fbe0805b2091393406952e84724188f8c1941837" # Linux kernel (Ubuntu package) KERNEL_VERSION="6.8.0-90" -KERNEL_PKG_SHA256="3c1fac8583c9ffee1d38985f6a4c2abaebda6852396ad70d1a8688dcab4ef1fc" +KERNEL_PKG_SHA256="19efb319503d92ecfc92a5e8c9ec5546461d88273b375203c3d4ebbd7ae1d61f" # Busybox (Ubuntu package, for initrd) BUSYBOX_PKG_VERSION="1:1.36.1-6ubuntu3.1" From d49355cad74a628e9053acb548d31a487dfa3e91 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 15:51:01 -0600 Subject: [PATCH 14/15] Resolve initrd input paths before directory changes --- misc/AMDSEV/build-initrd.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/misc/AMDSEV/build-initrd.sh b/misc/AMDSEV/build-initrd.sh index 5abf1ac04..f9b54343e 100755 --- a/misc/AMDSEV/build-initrd.sh +++ b/misc/AMDSEV/build-initrd.sh @@ -84,8 +84,17 @@ if [[ $# -lt 2 ]] || [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then usage fi -KATANA_BINARY="$1" -OUTPUT_INITRD="$2" +to_abs_path() { + local path="$1" + if [[ "$path" = /* ]]; then + printf '%s\n' "$path" + else + printf '%s/%s\n' "$(pwd -P)" "$path" + fi +} + +KATANA_BINARY="$(to_abs_path "$1")" +OUTPUT_INITRD="$(to_abs_path "$2")" KERNEL_VERSION="${3:-${KERNEL_VERSION:?KERNEL_VERSION must be set or passed as third argument}}" OUTPUT_DIR="$(dirname "$OUTPUT_INITRD")" From 692b779869b52b5a9a2ddbde70b382984f1f0760 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 26 Feb 2026 16:25:53 -0600 Subject: [PATCH 15/15] Resolve kernel output path before temp dir pushd --- misc/AMDSEV/build-kernel.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/misc/AMDSEV/build-kernel.sh b/misc/AMDSEV/build-kernel.sh index 6404b54dd..e1d2facce 100755 --- a/misc/AMDSEV/build-kernel.sh +++ b/misc/AMDSEV/build-kernel.sh @@ -51,7 +51,16 @@ if [[ $# -lt 1 ]] || [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then usage fi -DEST="$1" +to_abs_path() { + local path="$1" + if [[ "$path" = /* ]]; then + printf '%s\n' "$path" + else + printf '%s/%s\n' "$(pwd -P)" "$path" + fi +} + +DEST="$(to_abs_path "$1")" # Validate required environment variables KERNEL_VER="${KERNEL_VERSION:?KERNEL_VERSION not set - source build-config first}"