feat(tooling): fetch-authlib.sh to download authlib-injector.jar

The server JVM agent (runtime/authlib-injector.jar, mounted at /extras) is
gitignored and was previously fetched by the deleted build-stack.sh prep. A
fresh checkout had no jar, so minecraft crashlooped with "Error opening zip
file or JAR manifest missing". Add a standalone fetch tool: resolves the latest
release asset, downloads, and verifies it's a real zip/jar (PK magic) before
trusting it. Idempotent (skips if valid, --force to re-download). Wire it into
the deploy skill and README launch steps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 03:06:59 +02:00
parent cfd60131fb
commit a2821f2bbc
4 changed files with 59 additions and 3 deletions

View File

@@ -37,6 +37,7 @@ invoking this skill is the authorization to proceed, but:
cd /home/ubuntu/mc/ulicraft-server-v1 cd /home/ubuntu/mc/ulicraft-server-v1
git pull --ff-only git pull --ff-only
tooling/render-config.sh tooling/render-config.sh
tooling/fetch-authlib.sh
docker compose down --remove-orphans docker compose down --remove-orphans
docker compose up -d --build' docker compose up -d --build'
``` ```
@@ -45,6 +46,9 @@ invoking this skill is the authorization to proceed, but:
- `render-config.sh` re-renders drasl/nmsr/packwiz configs from `.env` - `render-config.sh` re-renders drasl/nmsr/packwiz configs from `.env`
(needs `.env` complete: `BASE_DOMAIN`, `RCON_PASSWORD`, (needs `.env` complete: `BASE_DOMAIN`, `RCON_PASSWORD`,
`DISTRIBUTION_WEB_ROOT`, `CADDY_HTTP_*`). `DISTRIBUTION_WEB_ROOT`, `CADDY_HTTP_*`).
- `fetch-authlib.sh` ensures `runtime/authlib-injector.jar` exists (gitignored;
skips if already valid). Missing jar = minecraft crashloops with "Error
opening zip file or JAR manifest missing".
3. **Verify.** 3. **Verify.**
```bash ```bash

View File

@@ -49,7 +49,7 @@ cp .env.example .env # set BASE_DOMAIN, RCON_PASSWORD, DISTRIBUTION_W
tooling/render-config.sh # drasl + nmsr + packwiz configs from *.tmpl tooling/render-config.sh # drasl + nmsr + packwiz configs from *.tmpl
( cd landing && pnpm install && BASE_DOMAIN="$BASE_DOMAIN" pnpm run build ) # → www/ ( cd landing && pnpm install && BASE_DOMAIN="$BASE_DOMAIN" pnpm run build ) # → www/
tooling/fetch-launcher.sh # FjordLauncher assets → launcher/ (served at /launcher/) tooling/fetch-launcher.sh # FjordLauncher assets → launcher/ (served at /launcher/)
# authlib-injector.jar → runtime/ (server JVM agent; see drasl docs) tooling/fetch-authlib.sh # authlib-injector.jar → runtime/ (server JVM agent)
docker compose up -d --build # first run installs NeoForge + mods, builds nmsr docker compose up -d --build # first run installs NeoForge + mods, builds nmsr
docker compose down # stop docker compose down # stop

View File

@@ -4,8 +4,9 @@ Runtime drop-ins mounted read-only into the Minecraft container at `/extras`.
## Required files ## Required files
- `authlib-injector.jar`download latest from - `authlib-injector.jar`fetch with `tooling/fetch-authlib.sh` (downloads the
https://github.com/yushijinhun/authlib-injector/releases latest from https://github.com/yushijinhun/authlib-injector/releases and
verifies it's a valid jar). Gitignored.
Mods are no longer listed here; the pack is served via packwiz Mods are no longer listed here; the pack is served via packwiz
(`PACKWIZ_URL`, see plan/04-packwiz.md). (`PACKWIZ_URL`, see plan/04-packwiz.md).

51
tooling/fetch-authlib.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# fetch-authlib.sh — download the latest authlib-injector.jar into runtime/.
#
# The Minecraft container mounts ./runtime read-only at /extras and loads the
# server JVM agent from /extras/authlib-injector.jar (points the server at Drasl
# for session validation). The jar is gitignored, so a fresh checkout needs this.
#
# Usage:
# tooling/fetch-authlib.sh # download if missing (or invalid)
# tooling/fetch-authlib.sh --force # re-download even if present
#
# Cautious by design: resolves the release asset by name, halts on any error,
# and verifies the result is a real zip/jar before trusting it (a half-written
# or HTML error body would otherwise surface later as the cryptic
# "Error opening zip file or JAR manifest missing").
set -euo pipefail
cd "$(dirname "$0")/.." # repo root
log() { printf '\n\033[1;32m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; }
command -v curl >/dev/null || die "curl required"
command -v jq >/dev/null || die "jq required"
DEST="runtime/authlib-injector.jar"
API="https://api.github.com/repos/yushijinhun/authlib-injector/releases/latest"
# A valid jar is a zip — first two bytes are "PK". Reject anything else.
is_jar() { [ -s "$1" ] && [ "$(head -c2 "$1" 2>/dev/null)" = "PK" ]; }
if [ "${1:-}" != "--force" ] && is_jar "$DEST"; then
log "$DEST already present and valid — skipping (use --force to re-download)"
exit 0
fi
log "resolving latest authlib-injector release asset"
url="$(curl -fsSL "$API" \
| jq -r '.assets[] | select(.name|test("authlib-injector-[0-9].*\\.jar$")) | .browser_download_url' \
| head -1)"
[ -n "$url" ] && [ "$url" != "null" ] || die "could not resolve authlib-injector release asset"
mkdir -p runtime
tmp="${DEST}.part"
log "downloading $(basename "$url")"
curl -fSL --retry 3 -o "$tmp" "$url"
is_jar "$tmp" || { rm -f "$tmp"; die "downloaded file is not a valid jar (zip) — aborting"; }
mv -f "$tmp" "$DEST"
log "done → $DEST ($(wc -c <"$DEST") bytes)"