Minesweeper X under wine on a headless display, as a plugin. It was /api/minesweeper, a Dashboard screen, an officerdev panel, a permission registry entry and a hand-written websocket provider in server.tsx. The socket is why it had to live in the platform: Bun's route table is fixed at serve(), so nothing installed later could add one. That ceiling is gone, and this is the first plugin through the per-plugin relay. Three things changed rather than moved: The sidecar owns the session. The platform used to spawn bin/session.sh detached, so the game outlived every restart, nothing supervised it, and a crashed run left wine processes holding the prefix — the next start hung rather than failed. PM2 supervises a sidecar, and stop() uses 'wineserver -k' scoped by WINEPREFIX instead of 'pkill -f wineserver', which would have killed every other wine prefix on the machine. x11vnc moved from 127.0.0.1:5907 to a unix socket in a mode-0700 directory. -nopw was only ever safe because of the machine, not the platform: any local account could open that port and take the display. A fixed port is squattable too. There is now no listener to authenticate against. The wine prefix is confined to C:. This is the one that mattered. The platform classified Minesweeper as kind:'execution' — never grantable — because a fresh prefix maps the whole filesystem to Z: and symlinks the profile into the owner's real home, and the game has Open and Save dialogs. A plugin permission has no kind and is always grantable, so extracting it without this would have converted a sealed capability into a file picker running as the owner. Re-asserted on every start, because wine restores z: whenever it updates a prefix. Not solved: one display and one game, so two grantees share a board. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
66 lines
3.0 KiB
Markdown
66 lines
3.0 KiB
Markdown
# Minesweeper
|
|
|
|
Minesweeper X, running under wine on a headless X display, streamed into an Officer panel.
|
|
|
|
It is a game. It is also the smallest honest proof that Officer can put an arbitrary X11 program in a
|
|
panel — a framebuffer, a process on it, a VNC server reading it, a client in the browser — and it is the
|
|
first plugin to use the platform's per-plugin websocket relay.
|
|
|
|
## What it needs
|
|
|
|
Six host binaries, declared in `manifest.ts` and checked before install: `wine`, `Xvfb`, `x11vnc`,
|
|
`xdotool`, `xdpyinfo`, `winetricks`.
|
|
|
|
The awkward one is wine. Minesweeper X is a **32-bit** PE (machine `0x014c`, Visual Basic 6), so the host
|
|
needs i386 multiarch and a `win32` prefix. A 64-bit-only wine cannot load it, and the failure is a bare
|
|
`Bad EXE format`. On Debian or Ubuntu:
|
|
|
|
```
|
|
sudo dpkg --add-architecture i386
|
|
sudo apt update
|
|
sudo apt install wine wine32:i386 xvfb x11vnc x11-utils xdotool winetricks
|
|
```
|
|
|
|
## The game
|
|
|
|
[Minesweeper X](https://minesweepergame.com/download/minesweeper-x.zip) — the competition build, with
|
|
timing and replay extras. `game/Minesweeper X.exe` is committed; it is 68 KB and it is the thing being
|
|
run rather than state produced by running it.
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| zip sha256 | `21089193924919ef876a5b464f06bed9cc149867c51e40c259288ebe623014f0` |
|
|
| exe sha256 | `e414c207adaa14999b0464c3d0a701f20ed11282d5ed0f84b27b62d25389f661` |
|
|
|
|
The download needs a browser `User-Agent`; the site answers `403` to curl's default.
|
|
|
|
## Where its state lives
|
|
|
|
`DATA_PATH/minesweeper/` — never in this directory, which `plugins:update` will `git pull` over.
|
|
|
|
- `prefix/` — the wine prefix, ~600 MB, built on first `POST /start`. Deleting it is the standard fix for
|
|
a wedged wine, and it is safe: the next start rebuilds it.
|
|
- `run/` — pid state, logs, and `vnc.sock`. **Mode 0700, and that is load-bearing.**
|
|
|
|
## Two things worth knowing before you change anything
|
|
|
|
**x11vnc has no password, and that is correct.** It binds a unix socket inside `run/`, not a port. The
|
|
kernel refuses every other account before x11vnc is asked anything, so a password would be a second lock
|
|
on a door only one person can reach. The version this replaced bound `127.0.0.1:5907` with `-nopw`, which
|
|
is a different claim entirely — every local account could open it and take the display.
|
|
|
|
**The wine prefix is confined to `C:` on every start.** A fresh prefix maps the whole filesystem to `Z:`
|
|
and symlinks the profile into the real home, and Minesweeper X has Open and Save dialogs for its replays.
|
|
That is why this was an ungrantable `execution` capability in the platform. `sidecar/prefix.ts` closes it
|
|
instead, which is what makes the plugin's permission safe to grant. Wine restores `z:` whenever it updates
|
|
a prefix, so the confinement is re-asserted rather than done once.
|
|
|
|
## Contract
|
|
|
|
```
|
|
GET /api/minesweeper/status { installed, running, window, error? }
|
|
POST /api/minesweeper/start idempotent; builds the prefix on a cold install (minutes)
|
|
POST /api/minesweeper/stop
|
|
/api/plugin-ws/minesweeper the display, as RFB
|
|
```
|