()
| 62 | }; |
| 63 | |
| 64 | const provisionLinux = async (): Promise<ProvisionedGuest> => { |
| 65 | ensureBundle(); |
| 66 | const { dir } = hostBundle(); |
| 67 | const vm = await tartVm("linux", "arm64").provision(); |
| 68 | try { |
| 69 | await vm.ssh(`rm -rf ${GUEST_DIR} ${GUEST_HOME}; mkdir -p ${GUEST_HOME}/.executor`); |
| 70 | await pushDirAsTar(vm.host, dir, GUEST_DIR); |
| 71 | |
| 72 | const guestApp = `${GUEST_DIR}/${basename(dir)}`; |
| 73 | const guestExe = `${guestApp}/executor-desktop`; |
| 74 | const guestExecutor = `${guestApp}/resources/executor/executor`; |
| 75 | await vm.ssh(`chmod +x '${guestExe}' '${guestExecutor}' 2>/dev/null || true`); |
| 76 | const env = `HOME=${GUEST_HOME} EXECUTOR_DATA_DIR=${GUEST_HOME}/.executor`; |
| 77 | |
| 78 | // A virtual display + a minimal WM (openbox) — without a window manager the |
| 79 | // electron window doesn't map onto the framebuffer that x11grab records. |
| 80 | await vm.ssh( |
| 81 | `pkill Xvfb 2>/dev/null; pkill openbox 2>/dev/null; ` + |
| 82 | `nohup Xvfb ${DISPLAY} -screen 0 1280x800x24 >/tmp/xvfb.log 2>&1 & sleep 2; ` + |
| 83 | `DISPLAY=${DISPLAY} nohup openbox >/tmp/openbox.log 2>&1 & sleep 1; echo up`, |
| 84 | ); |
| 85 | |
| 86 | // 1) the bundled daemon, supervised — the app attaches to this. |
| 87 | await vm.ssh( |
| 88 | `nohup env ${env} EXECUTOR_SUPERVISED=1 EXECUTOR_AUTH_TOKEN=desktop-linux-e2e EXECUTOR_CLIENT=desktop ` + |
| 89 | `'${guestExecutor}' daemon run --foreground --port ${DAEMON_PORT} --hostname 127.0.0.1 ` + |
| 90 | `>/tmp/executor-daemon.log 2>&1 &`, |
| 91 | ); |
| 92 | if (!(await waitGuestHttp(vm, `http://127.0.0.1:${DAEMON_PORT}/`))) { |
| 93 | throw new Error( |
| 94 | "supervised daemon never came up in the guest (see /tmp/executor-daemon.log)", |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | // 2) the packaged app on the virtual display, with CDP enabled. |
| 99 | await vm.ssh( |
| 100 | `nohup env ${env} DISPLAY=${DISPLAY} '${guestExe}' --no-sandbox ` + |
| 101 | `--remote-debugging-port=${CDP_GUEST_PORT} --remote-allow-origins='*' ` + |
| 102 | `>/tmp/executor-app.log 2>&1 &`, |
| 103 | ); |
| 104 | if (!(await waitGuestPageTarget(vm, CDP_GUEST_PORT))) { |
| 105 | const log = (await vm.ssh("tail -40 /tmp/executor-app.log 2>/dev/null").catch(() => null)) |
| 106 | ?.stdout; |
| 107 | throw new Error(`the app's CDP page target never appeared:\n${log ?? "(no app log)"}`); |
| 108 | } |
| 109 | |
| 110 | // The electron window maps tiny (10x10) under Xvfb; size it to the screen so |
| 111 | // the x11grab recording captures the full console (CDP screenshots the |
| 112 | // renderer surface regardless, but the film grabs the X framebuffer). |
| 113 | await vm.ssh( |
| 114 | `WID=$(DISPLAY=${DISPLAY} xdotool search --name executor-desktop | head -1); ` + |
| 115 | `[ -n "$WID" ] && DISPLAY=${DISPLAY} xdotool windowsize "$WID" 1280 800 windowmove "$WID" 0 0 || true`, |
| 116 | ); |
| 117 | |
| 118 | return { ip: vm.host, teardown: async () => void (await vm.discard()) }; |
| 119 | } catch (error) { |
| 120 | await vm.discard(); |
| 121 | throw error; |
nothing calls this directly
no test coverage detected