#!/bin/sh # Build a deterministic, non-secret Windows test bundle for one harness run. # It deliberately does not sign or publish artifacts; those are release gates. set -eu repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd) usage() { cat <<'EOF' usage: scripts/windows/build-test-bundle --run-id ID --config FILE [--ca FILE] [--no-build] [--native-fixture] Builds bin/rvbox.exe in the pinned Docker toolchain, then creates exactly: .test-runs/ID/windows-bundle/{rvbox.exe,client.toml[,ca.pem],manifest.sha256} The bundle is for the resettable native-test fixture only. The config must use the target guest paths and the declared test nginx endpoint. Existing bundles are refused rather than overwritten. --native-fixture compiles the Windows executable with the rvbox_native_test tag. That non-release binary alone accepts --test-fail-contexts, used only to prove pre-launch elevation fallback order in the disposable VM. EOF } fail() { printf '%s\n' "build-test-bundle: $*" >&2; exit 2; } run_id= config= ca= build=yes native_fixture=no while [ "$#" -gt 0 ]; do case $1 in --run-id) [ "$#" -ge 2 ] || fail "--run-id needs a value"; run_id=$2; shift 2 ;; --config) [ "$#" -ge 2 ] || fail "--config needs a file"; config=$2; shift 2 ;; --ca) [ "$#" -ge 2 ] || fail "--ca needs a PEM file"; ca=$2; shift 2 ;; --no-build) build=no; shift ;; --native-fixture) native_fixture=yes; shift ;; --help|-h) usage; exit 0 ;; *) fail "unknown argument $1" ;; esac done case $run_id in [a-z0-9]* ) ;; * ) fail "run ID must start with lowercase alphanumeric" ;; esac case $run_id in ''|*[!a-z0-9-]*|????????????????????????????????????????????????????????????????*) fail "run ID must match [a-z0-9][a-z0-9-]{0,63}" ;; esac [ -f "$config" ] && [ ! -L "$config" ] || fail "--config must be a regular non-symlink file" if [ -n "$ca" ]; then [ -f "$ca" ] && [ ! -L "$ca" ] || fail "--ca must be a regular non-symlink file"; fi if [ "$build" = yes ]; then "$repo_root/scripts/build" build; fi if [ "$native_fixture" = yes ]; then # Keep the server/rvc artifacts produced by scripts/build, but replace only # the disposable test client with its explicitly tagged fixture build. # No host Go toolchain is used. Strip symbol/DWARF tables because this # disposable binary is transferred to the remote VM fixture; this does not # change executable behavior or the tagged test boundary. docker compose -f "$repo_root/deploy/compose.yaml" run --rm toolchain \ env GOOS=windows GOARCH=amd64 go build -trimpath -tags rvbox_native_test -ldflags '-H=windowsgui -s -w' -o bin/rvbox.exe ./cmd/rvbox fi binary=$repo_root/bin/rvbox.exe [ -f "$binary" ] && [ ! -L "$binary" ] || fail "expected regular Windows binary at bin/rvbox.exe" bundle=$repo_root/.test-runs/$run_id/windows-bundle mkdir -p "$repo_root/.test-runs/$run_id" if ! mkdir "$bundle"; then fail "refusing to overwrite existing bundle $bundle" fi trap 'rmdir "$bundle" 2>/dev/null || true' INT TERM HUP install -m 700 "$binary" "$bundle/rvbox.exe" install -m 600 "$config" "$bundle/client.toml" if [ -n "$ca" ]; then install -m 600 "$ca" "$bundle/ca.pem"; fi commit=$(git -C "$repo_root" rev-parse HEAD) { printf 'run_id=%s\n' "$run_id" printf 'git_commit=%s\n' "$commit" printf 'native_fixture=%s\n' "$native_fixture" (cd "$bundle" && sha256sum rvbox.exe client.toml ${ca:+ca.pem}) } >"$bundle/manifest.sha256" chmod 600 "$bundle/manifest.sha256" trap - INT TERM HUP printf 'bundle=%s\n' "$bundle"