1+ name : playground-test
2+
3+ on :
4+ workflow_dispatch :
5+ inputs :
6+ image-run-id :
7+ description : " Reuse image from a previous run (skip build). Leave empty to build fresh."
8+ type : string
9+ default : " "
10+ builder-playground-ref :
11+ description : " builder-playground git ref (branch/tag/sha)"
12+ default : " fryd/buildernet-improvements"
13+ type : string
14+
15+ jobs :
16+ build :
17+ name : Build playground image
18+ if : inputs.image-run-id == ''
19+ runs-on : warp-ubuntu-2404-x64-32x
20+ timeout-minutes : 30
21+ steps :
22+ - uses : actions/checkout@v5
23+
24+ - name : Install mkosi
25+ run : |
26+ sudo apt-get update && sudo apt-get install -y debian-archive-keyring
27+ pip3 install git+https://github.com/systemd/mkosi.git@$(cat .mkosi_version)
28+
29+ - name : Enable user namespaces
30+ run : sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
31+
32+ - name : Build image
33+ run : |
34+ umask 022
35+ mkosi --force -I buildernet.conf --profile="devtools,playground"
36+
37+ - name : Show output
38+ run : |
39+ ls -lah mkosi.output/
40+ sha256sum mkosi.output/buildernet-qemu_*.qcow2
41+
42+ - name : Upload image
43+ uses : actions/upload-artifact@v4
44+ with :
45+ name : buildernet-playground-image
46+ path : mkosi.output/buildernet-qemu_*.qcow2
47+ retention-days : 14
48+
49+ test :
50+ name : Test playground image
51+ needs : build
52+ if : always() && (needs.build.result == 'success' || needs.build.result == 'skipped')
53+ runs-on : warp-ubuntu-2404-x64-32x
54+ timeout-minutes : 30
55+ env :
56+ PLAYGROUND_REF : ${{ inputs.builder-playground-ref }}
57+ steps :
58+ - name : Check runner environment
59+ run : |
60+ echo "--- CPU ---"
61+ nproc
62+ echo "--- Memory ---"
63+ free -h
64+ echo "--- Disk ---"
65+ df -h
66+ echo "--- KVM ---"
67+ ls -la /dev/kvm 2>/dev/null && echo "KVM available" || echo "KVM NOT available"
68+ echo "--- Docker ---"
69+ docker --version 2>/dev/null || echo "Docker not installed"
70+
71+ - name : Download image
72+ uses : actions/download-artifact@v4
73+ with :
74+ name : buildernet-playground-image
75+ path : ./image
76+ run-id : ${{ inputs.image-run-id || github.run_id }}
77+ github-token : ${{ secrets.GITHUB_TOKEN }}
78+
79+ - name : Verify image
80+ run : |
81+ ls -lah ./image/
82+ sha256sum ./image/*.qcow2
83+
84+ - name : Install QEMU and OVMF
85+ run : |
86+ sudo apt-get update && sudo apt-get install -y \
87+ qemu-system-x86 ovmf jq unzip
88+ qemu-system-x86_64 --version
89+
90+ - name : Set up Go
91+ uses : actions/setup-go@v5
92+ with :
93+ go-version : " 1.25"
94+
95+ - name : Clone and build builder-playground
96+ run : |
97+ git clone --depth 1 --branch "${PLAYGROUND_REF}" \
98+ https://github.com/flashbots/builder-playground.git
99+ cd builder-playground
100+ mkdir -p "$HOME/.local/bin"
101+ go build -o "$HOME/.local/bin/builder-playground" ./main.go
102+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
103+
104+ - name : Verify builder-playground
105+ run : builder-playground version
106+
107+ - name : Generate project
108+ run : |
109+ mkdir playground-workspace && cd playground-workspace
110+ builder-playground generate buildernet/mkosi
111+ echo "Generated files:"
112+ find . -type f | sort
113+
114+ - name : Start playground
115+ env :
116+ BUILDERNET_IMAGE : ${{ github.workspace }}/image/buildernet-qemu_latest.qcow2
117+ QEMU_ACCEL : tcg
118+ QEMU_CPU : " 4"
119+ QEMU_RAM : 8G
120+ run : |
121+ cd playground-workspace
122+ builder-playground start --detached playground.yaml
123+
124+ - name : Wait for rbuilder RPC
125+ run : |
126+ WAIT_START=$(date +%s)
127+ WAIT_TIMEOUT=600
128+
129+ echo "Waiting for rbuilder RPC on localhost:18645 (timeout: ${WAIT_TIMEOUT}s)..."
130+ while true; do
131+ if curl -sf -m 5 -X POST http://localhost:18645 \
132+ -H 'Content-Type: application/json' \
133+ -d '{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}' > /dev/null 2>&1; then
134+ echo "rbuilder RPC ready after $(( $(date +%s) - WAIT_START ))s"
135+ break
136+ fi
137+ elapsed=$(( $(date +%s) - WAIT_START ))
138+ if [ "$elapsed" -ge "$WAIT_TIMEOUT" ]; then
139+ echo "Timed out after ${elapsed}s waiting for rbuilder RPC"
140+ exit 1
141+ fi
142+ echo " ${elapsed}s - not ready, retrying in 5s..."
143+ sleep 5
144+ done
145+
146+ cd playground-workspace
147+ echo "--- console log (last 50 lines) ---"
148+ tail -50 .runtime/console.log || true
149+
150+ - name : Run integration test
151+ run : |
152+ cd playground-workspace
153+ builder-playground test \
154+ --rpc http://localhost:18645 \
155+ --el-rpc http://localhost:8545 \
156+ --insecure \
157+ --expected-extra-data "Playground VM Builder ⚡🤖"
158+
159+ - name : Debug info
160+ if : always()
161+ run : |
162+ cd playground-workspace 2>/dev/null || true
163+
164+ echo "=== QEMU process ==="
165+ ps aux | grep qemu || echo "no qemu process"
166+
167+ echo "=== .runtime/ directory ==="
168+ ls -lah .runtime/ 2>/dev/null || echo "no .runtime/ directory"
169+
170+ echo "=== QEMU console log ==="
171+ cat .runtime/console.log 2>/dev/null || echo "no console.log"
172+
173+ echo "=== QEMU PID file ==="
174+ cat .runtime/qemu.pid 2>/dev/null || echo "no qemu.pid"
175+
176+ echo "=== Playground session logs ==="
177+ SESSION_DIR=$(ls -td ~/.local/state/builder-playground/sessions/*/ 2>/dev/null | head -1)
178+ if [ -n "$SESSION_DIR" ]; then
179+ echo "Session dir: $SESSION_DIR"
180+ find "$SESSION_DIR/logs" -type f 2>/dev/null | while read -r f; do
181+ echo "--- ${f#$SESSION_DIR/logs/} ---"
182+ cat "$f"
183+ done
184+ else
185+ echo "no session directory found"
186+ fi
187+
188+ echo "=== VM service logs (via operator-api) ==="
189+ curl -sk https://localhost:13535/logs 2>/dev/null || echo "operator-api not reachable"
190+
191+ echo "=== Docker containers ==="
192+ docker ps -a 2>/dev/null || true
193+
194+ echo "=== Disk ==="
195+ df -h
196+
197+ - name : Cleanup
198+ if : always()
199+ run : |
200+ cd playground-workspace 2>/dev/null || true
201+ builder-playground clean all 2>/dev/null || true
0 commit comments