feat(installer): implement Phase 1 — the installer core
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m31s
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m31s
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>
This commit is contained in:
@@ -7,12 +7,12 @@
|
||||
# The one structural difference is the crate guard below.
|
||||
#
|
||||
# ── Crate guard ──────────────────────────────────────────────────────────────
|
||||
# This repo is in the planning phase and has no Cargo project yet (the design of
|
||||
# record is docs/installer/PLAN.md; Phase 1 is what creates the crate). Rather
|
||||
# than leave the repo ungated until then — or land a workflow that red-Xes every
|
||||
# governance/docs PR — the gates are conditional on a root Cargo.toml existing.
|
||||
# Before the crate lands, the job reports green with a notice. The moment
|
||||
# Phase 1 adds Cargo.toml the gates arm themselves; nothing here has to change.
|
||||
# The gates are conditional on a root Cargo.toml existing: before the crate
|
||||
# landed, this job reported green with a notice so governance/docs PRs were not
|
||||
# red-Xed by a workflow with nothing to build. Phase 1 has now added the crate on
|
||||
# `edge`, so the gates arm themselves there automatically — and stay dormant on
|
||||
# a `main` PR until the cutover merges the crate into it. Nothing here changes at
|
||||
# that point either.
|
||||
#
|
||||
# The crate is expected at the REPO ROOT (not a subdirectory like link/sidecar):
|
||||
# this repo's sole product is the one installer binary, so there is nothing to
|
||||
@@ -35,7 +35,12 @@ name: PR Checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
# `edge` is gated as well as `main`. Phase 1 and 2 land there rather than on `main` so that
|
||||
# release.yml — which fires on every push to `main` — does not publish an installer binary that
|
||||
# can deploy the overlay but not yet install the sidecar. Ungating the branch where all the
|
||||
# work actually happens would leave the gates running only at the cutover, which is the one
|
||||
# moment a red build is most expensive.
|
||||
branches: [main, edge]
|
||||
|
||||
# A newer push to the same PR cancels the in-flight run.
|
||||
concurrency:
|
||||
|
||||
@@ -21,10 +21,14 @@
|
||||
# • Artifact names follow docs/installer/PLAN.md §3.
|
||||
#
|
||||
# ── Crate guard ──────────────────────────────────────────────────────────────
|
||||
# The repo is in the planning phase. With no Cargo.toml there is nothing to
|
||||
# build, so the plan step forces RELEASE=false and the job exits green having
|
||||
# done nothing. It starts cutting real releases the moment Phase 1 lands the
|
||||
# crate — no edit required here.
|
||||
# With no Cargo.toml at the repo root there is nothing to build, so the plan step
|
||||
# forces RELEASE=false and the job exits green having done nothing.
|
||||
#
|
||||
# That guard is what makes the `edge` branch work. Phase 1 (installer core) and
|
||||
# Phase 2 (sidecar + service) land on `edge`, so `main` stays crate-free and this
|
||||
# workflow keeps standing down — an installer binary that syncs the overlay but
|
||||
# cannot install the sidecar is not something to publish to operators. The first
|
||||
# release is cut by the `edge → main` cutover, with no edit required here.
|
||||
#
|
||||
# ── Unsigned releases ────────────────────────────────────────────────────────
|
||||
# Per PLAN.md §3, installer binaries are deliberately UNSIGNED: SHA256SUMS is
|
||||
|
||||
Reference in New Issue
Block a user