Some checks failed
PR Checks / rust-gates (pull_request) Failing after 46s
Two features need edits to stock ServUO sources, because the events they depend on do not exist. This adds the rung ladder of PLAN.md §2.2.1, the unsupported-version path of §2.2.2, and the record and cache Phase 4 will read. Three decisions were not settled by the plan: * The engine is fully native, with no `git`. §2.2.1 wrote rung 1 as "apply verbatim with git apply", but §1 chose the release tarball specifically so there would be no git on the shard host, and rung 2 needs a native applier regardless. Rung 1 keeps its distinct, stronger verdict — the whole file reproduced the diff's `index` pre-image, computed as a git blob SHA1 in process — while the write goes through the same code path as rung 2. On the real trees here that is not academic: the shipped .patch files are CRLF in a Windows checkout and two of their three targets are LF, so `git apply` refuses patches this applies correctly. * Per-patch metadata is declared by the release, with a built-in fallback. Which patches form one all-or-nothing unit, which companion .cs follows which, whether a CORE rebuild is needed and what declining costs are not derivable from a diff. servuo-plugins now declares them; overlay v0.1.1 is in the current bundle and declares nothing, so a built-in copy stands in for it. A checked-in fixture of the release workflow's own jq output asserts the two descriptions are identical, so the repos cannot drift quietly. * Pre-images are cached in the state directory. The tier edits files the operator owns, and `/etc/runicgateway/patches/originals/` is what turns "here are the hunks we added" into a revert anyone can verify — kept out of the ServUO tree, which uninstall has promised never to clean up. Everything else follows §2.2.1: exact matching with only line-ending and trailing-whitespace normalization, exactly one occurrence or it fails, all-or-nothing per patch file and again per feature, and a byte-preserving splice so nothing outside a hunk can be reformatted. Verified against the ServUO 57.4 tree on this machine across four scratch roots: a hand-patched tree (rung 0), a reverse-applied stock one (rung 1 on the real EventSink.cs, its blob matching the patch's declared pre-image), a mixed-rung feature, a tree with edits inside two patched regions (rung 3 — nothing written, nothing held back applied, no companions copied), and a non-57.4 tree both with and without the extra consent flag. Three consecutive runs left install.json byte-identical and the cached pre-image still pre-patch. Three reporting defects the live runs caught are fixed with tests: a dry run and a held-back patch both claimed to be "applied", the core-rebuild warning fired when nothing had been written and named a Scripts file as core, and a declined tier announced the loss of features install.json showed as applied. Refused patches are now cached too, since the refusal message names that path. Refs: docs/installer/PLAN.md §2.2, §5 Phase 3 Co-Authored-By: Claude <noreply@anthropic.com>
67 lines
2.9 KiB
TOML
67 lines
2.9 KiB
TOML
[package]
|
|
name = "runicgateway-installer"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
description = "Deployment tool for Runic Gateway: syncs the ServUO plugin overlay, installs the uo-link sidecar, and records what it deployed."
|
|
license = "GPL-3.0-or-later"
|
|
repository = "https://gitea.whitlocktech.com/RunicGateway/installer"
|
|
|
|
# The published binary keeps the name PLAN.md §3 and INSTALL.md give it. The library it is built
|
|
# from does not share that name on purpose: 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 called `runicgateway_installer` makes `cargo test`
|
|
# unrunnable on Windows. `test = false` keeps Cargo from building a harness under the binary's
|
|
# name; all the code, and all the tests, live in the library. See src/lib.rs.
|
|
[lib]
|
|
name = "rgdeploy"
|
|
path = "src/lib.rs"
|
|
|
|
[[bin]]
|
|
name = "runicgateway-installer"
|
|
path = "src/main.rs"
|
|
test = false
|
|
|
|
[dependencies]
|
|
# Blocking HTTP over a pure-Rust TLS stack (rustls + ring + webpki-roots). The
|
|
# release cross-compiles to x86_64-pc-windows-gnu through MinGW, where anything
|
|
# linking OpenSSL turns a one-line build into a toolchain project — and this tool
|
|
# makes a handful of sequential requests, so an async runtime would be overhead
|
|
# with nothing to overlap.
|
|
ureq = "3.3"
|
|
|
|
# Overlay releases ship as gzipped tar. flate2's default backend is miniz_oxide
|
|
# (pure Rust), so it cross-compiles with no C dependency of its own.
|
|
flate2 = "1"
|
|
tar = "0.4"
|
|
|
|
# SHA256 is the entire trust anchor for these deliberately unsigned artifacts
|
|
# (PLAN.md §3), which makes this load-bearing rather than a nicety.
|
|
sha2 = "0.11"
|
|
|
|
# SHA1 is here for one reason only: a patch's `index <old>..<new>` line carries
|
|
# git blob hashes, and reproducing one is how the patch tier answers rung 1 —
|
|
# "is this whole file still stock?" (PLAN.md §2.2.1). It is never used as a
|
|
# security primitive. Computing it natively is what keeps `git` off the shard
|
|
# host, which is the whole point of shipping the plugin as a release tarball.
|
|
sha1 = "0.11"
|
|
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
|
|
# RFC 3339 timestamps for install.json. Same feature set link's sidecar uses.
|
|
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
|
|
|
|
# Refusing to deploy under a running shard is a correctness requirement, not a
|
|
# courtesy: ServUO holds Scripts.dll open and rewrites Saves/ on exit. Only the
|
|
# `system` feature is wanted — disks, networks and users are not our business.
|
|
sysinfo = { version = "0.38", default-features = false, features = ["system"] }
|
|
|
|
# Error plumbing, as in link's sidecar. Every failure here is read by an operator
|
|
# rather than matched on, so a chain of `.context()` strings is the whole
|
|
# requirement — the value is that "failed to write install.json" arrives with the
|
|
# path and the OS error attached instead of alone.
|
|
anyhow = "1"
|
|
|
|
[profile.release]
|
|
opt-level = 2
|