From 6742dcb88a6ecca09430b78caa39b62b0ba41418 Mon Sep 17 00:00:00 2001 From: Andrew DiZenzo <59515127+andrewtdiz@users.noreply.github.com> Date: Sat, 23 May 2026 01:08:35 -0700 Subject: [PATCH] Guard hub builds against vulnerable Perry runtime --- .gitignore | 1 + CLAUDE.md | 7 +++-- README.md | 14 +++++++-- scripts/build.sh | 10 +++++++ scripts/check-perry-runtime.sh | 54 ++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 4 deletions(-) create mode 100755 scripts/build.sh create mode 100755 scripts/check-perry-runtime.sh diff --git a/.gitignore b/.gitignore index 46bcbf6..40e84c6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /test_ws.ts deploy.sh package.json +src/.perry-cache/ diff --git a/CLAUDE.md b/CLAUDE.md index 31d0679..3f71ed4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,13 +17,14 @@ for windows-sign). ``` src/main.ts # Entire server (single file) perry.toml # Perry compiler project config +scripts/build.sh # Guarded build entry point perry-hub # Compiled binary (gitignored) ``` ## Build & Run ```sh -# Compile (requires perry compiler) -~/projects/perry/target/release/perry compile src/main.ts -o perry-hub +# Compile with Perry 0.5.1026+. +PERRY=~/projects/perry/target/release/perry scripts/build.sh perry-hub # Run ./perry-hub @@ -41,6 +42,8 @@ limitations that heavily influence code style: - **No binary data in HTTP bodies** — pass file paths instead - **`crypto.randomUUID()`** instead of `crypto.randomBytes().toString('hex')` - **WebSocket**: use server-level events (`wss.on`), not per-connection (`ws.on`) +- **Build through `scripts/build.sh`** so hub cannot be rebuilt with Perry + 0.5.1025's GC unsafe-zone runtime regression. See memory file `perry-quirks.md` for the full list. diff --git a/README.md b/README.md index af350b2..1eed6e4 100644 --- a/README.md +++ b/README.md @@ -58,15 +58,25 @@ The Azure VM auto-deallocates after 30 minutes of idle time, so compute billing ``` src/main.ts # Entire server (single file) perry.toml # Perry compiler project config +scripts/build.sh # Guarded build entry point perry-hub # Compiled binary (gitignored) ``` ## Building -Requires the [Perry compiler](https://github.com/PerryTS/perry): +Requires the [Perry compiler](https://github.com/PerryTS/perry) version +0.5.1026 or newer. Perry 0.5.1025 predates the runtime GC unsafe-zone fix that +this long-running Fastify/WebSocket server needs to keep its periodic `gc()` +safety valve effective. ```sh -perry compile src/main.ts -o perry-hub +scripts/build.sh +``` + +To build with a local Perry checkout: + +```sh +PERRY=~/projects/perry/target/release/perry scripts/build.sh perry-hub ``` ## Running diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..4b11437 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PERRY_BIN="${PERRY:-perry}" +OUT="${1:-$ROOT/perry-hub}" + +"$ROOT/scripts/check-perry-runtime.sh" + +exec "$PERRY_BIN" compile "$ROOT/src/main.ts" -o "$OUT" --no-cache diff --git a/scripts/check-perry-runtime.sh b/scripts/check-perry-runtime.sh new file mode 100755 index 0000000..628fb4c --- /dev/null +++ b/scripts/check-perry-runtime.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euo pipefail + +MIN_PERRY_VERSION="0.5.1026" +PERRY_BIN="${PERRY:-perry}" + +version_ge() { + local have_major have_minor have_patch + local want_major want_minor want_patch + + IFS=. read -r have_major have_minor have_patch <<< "$1" + IFS=. read -r want_major want_minor want_patch <<< "$2" + + [[ "$have_major" =~ ^[0-9]+$ ]] || return 1 + [[ "$have_minor" =~ ^[0-9]+$ ]] || return 1 + [[ "$have_patch" =~ ^[0-9]+$ ]] || return 1 + [[ "$want_major" =~ ^[0-9]+$ ]] || return 1 + [[ "$want_minor" =~ ^[0-9]+$ ]] || return 1 + [[ "$want_patch" =~ ^[0-9]+$ ]] || return 1 + + (( have_major > want_major )) && return 0 + (( have_major < want_major )) && return 1 + (( have_minor > want_minor )) && return 0 + (( have_minor < want_minor )) && return 1 + (( have_patch >= want_patch )) +} + +if ! version_output="$("$PERRY_BIN" --version 2>/dev/null)"; then + echo "error: unable to execute Perry compiler: $PERRY_BIN" >&2 + echo "Set PERRY=/path/to/perry or put Perry on PATH." >&2 + exit 1 +fi + +version="${version_output#perry }" +version="${version%% *}" +version_core="${version%%-*}" +version_core="${version_core%%+*}" + +if ! version_ge "$version_core" "$MIN_PERRY_VERSION"; then + cat >&2 <= $MIN_PERRY_VERSION. + +Found: $version_output + +Perry 0.5.1025 predates the GC unsafe-zone runtime fix needed by this +long-running Fastify/WebSocket server. That runtime can suppress the hub's +periodic manual gc() safety valve while still allowing automatic GC in native +server callbacks, which reintroduces the leak/crash reported in Perry issue +#1467. Rebuild Perry from main after PerryTS/perry#1429, then rebuild hub. +EOF + exit 1 +fi + +echo "Using $version_output"