Step 4 of PLAN.md §5.2, and the half that faces the operator: the
release now cross-compiles aarch64-unknown-linux-gnu, and platform_key()
resolves ("linux","aarch64") to the bundle key link publishes under
instead of refusing the host by name.
Same toolchain shape as the Windows step -- a linker plus a CC/AR pair,
because ring (under ureq's rustls) compiles C and assembly. And the same
packaging trap named in the sums comment: an artifact missing from
SHA256SUMS is one `sha256sum -c` passes over silently, so the new binary
is added to both the sums and the upload list.
Two test changes fall out of the asset map growing a key:
- The exact `assets.len() == 2` assertion is replaced by a check that
each key CI requires is present and well-formed. An exact count would
fail on the first bundle that adds arm64 -- reporting correct
behaviour as a regression.
- The host-binary lookup now accepts either outcome, and says why.
Bundles are kept unchanged forever so `--bundle` stays reproducible,
which means one published before arm64 existed can never gain that
key. On such a host the run must fail with the reason rather than
something that reads like a corrupt document, so sidecar_asset()'s
error now says so and the test asserts it.
Verified by cross-building this crate for aarch64 in a
rust:1-slim-bookworm container -- ELF 64-bit LSB pie executable, ARM
aarch64 -- and by running fmt, clippy -D warnings and the tests on both
Linux and the Windows host, since only half of service.rs compiles on
either.
Co-Authored-By: Claude <noreply@anthropic.com>
Adds the Rust crate at the repo root and implements `install` end to end for
the overlay half of a deployment: resolve the published bundle, find and
validate the ServUO root, refuse to deploy under a running shard, sync the
plugin overlay, and record what was deployed in install.json.
`doctor`, `update` and `uninstall` parse and answer with the phase they arrive
in rather than "unrecognized command", and the run states plainly that the
uo-link sidecar (Phase 2) and the patch tier (Phase 3) were not installed —
`--patches` in particular reports REQUESTED BUT NOT APPLIED, since a quiet
completion would be read as a patched shard.
Landing on `edge` rather than `main`: release.yml publishes a binary on every
push to main, and an installer that deploys the overlay but cannot install the
sidecar is not something to hand an operator. pr-checks.yml now gates PRs into
edge on the same rules, so the branch the work happens on is not the ungated
one.
Notable decisions, all documented in docs/installer/PLAN.md §5 Phase 1:
- The code lives in a library called `rgdeploy` with a thin binary that keeps
the published name. Windows' UAC installer detection refuses to launch an
unsigned executable whose file name contains "install" (os error 740), and
Cargo names test harnesses after their target — so a target under that name
makes `cargo test` unrunnable on Windows.
- The running-shard check matches processes by path, not by process name:
on Linux a live shard is `mono`/`dotnet` with ServUO.exe as an argument, and
a name match would report "not running" for a shard that is running.
- install.json records a state (`deployed` / `kept-operator-modified`), not the
run's verb, so an unchanged re-run produces an identical record and writes
nothing.
- The Bridge.cfg keep rule compares against the hash the installer last
deployed, not the last hash it saw — otherwise a kept file is overwritten on
the very next run.
- Downloads are verified against the bundle's SHA256 while being written, then
every extracted file is re-hashed against the release's own manifest.json,
whose protocol and version are cross-checked against the bundle.
Verified against a real ServUO 57.4 tree and end to end into a scratch tree:
24 files deployed, an unchanged re-run that writes nothing, an edited
Bridge.cfg kept across repeated runs while code files are overwritten, bundle
pinning, and a refusal with a shard running out of the tree.
Co-Authored-By: Claude <noreply@anthropic.com>