feat(installer): implement Phase 1 — the installer core #4
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/phase1-installer-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What & why
Phase 1 of
docs/installer/PLAN.md— the installer core. Adds the Rust crate at the repo root and implementsinstallend to end for the overlay half of a deployment:bundles/current.json, or--bundle <tag>to pin one),manifest.json,Config/Bridge.cfgreported, not clobbered once the operator has edited it,install.json, and re-run idempotently.doctor/update/uninstallparse and answer with the phase they arrive in rather than "unrecognized command". The run also states what it did not do: the sidecar (Phase 2) is named as not installed, with the bundle's binary URL + SHA256 and a pointer to INSTALL.md A3/A4, and--patchesreportsREQUESTED BUT NOT APPLIED — no stock ServUO file has been touched, because a--patchesrun that completed quietly would be read as a patched shard.Targets
edge, notmain, on purpose.release.ymlpublishes an installer binary on every push tomain, and a binary that deploys the overlay but cannot install the sidecar is not something to hand an operator. Phases 1 and 2 land onedge; theedge → maincutover cuts the first release.pr-checks.ymlnow gates PRs intoedgeon the same rules, so the branch the work happens on is not the ungated one. Neither workflow needed a temporary edit — both already stand down when there is no rootCargo.toml.Decisions worth a reviewer's attention
rgdeploy, notrunicgateway_installer. Windows applies UAC installer detection to unsigned executables whose file name containsinstall: it demands elevation before the process starts, and a non-interactive session getsos error 740instead of a program. Cargo names test harnesses after their target, so a target under that name makescargo testunrunnable on Windows — the machine the shard smoke tests live on. The binary target keeps its published name and[[bin]] test = falsestops Cargo building a harness under it. Nothing an operator sees changes; INSTALL.md gains a troubleshooting row for the elevation prompt.deploy.ps1looks for a process calledServUObecause it only runs on Windows; on Linux a live shard ismono/dotnetwithServUO.exeas an argument, and a name match would answer "not running" for a shard that is running — the one wrong answer that corruptsScripts.dll. A match needs a process naming both this tree andServUO.exe, so another shard on the host does not block the deploy and the installer never matches itself.install.jsonrecords a state, not a verb (deployed/kept-operator-modified). Recordingaddthenunchangedmade an identical re-run produce a different record, which rewrote the file every run and broke "a second run writes nothing" invisibly.Bridge.cfgkeep compares against the last hash deployed, not the last hash seen. After a keep, the record's on-disk hash is the operator's content — so "is the tree still what the record last saw?" matches on the very next run and overwrites exactly the file the rule protects. Both of these were found by the live smoke run, not by the unit tests, and both now have tests.ureq(blocking HTTP over rustls/ring — no OpenSSL, no async runtime for four sequential requests),flate2on its pure-Rust backend,tar,sha2,serde,chrono,anyhow,sysinfo.Docs half: docs#90 (
docs(installer): record Phase 1 as built).How it was tested
cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test— 50 tests, all green.End to end, with the binary copied under a neutral name (see the UAC note above):
--verifyagainst a real ServUO 57.4 tree (C:\Users\colby\Desktop\ServUO): bundle fetched over the network, tarball downloaded and checksum-verified, version detected as 57.4, and the tree read correctly — itsBridge.cfgreported as operator-owned, 23 code files as changed, nothing written.install.jsonwritten with 24 per-file entries.unchanged. add=0 change=0 unchanged=24 kept=0and leavesinstall.jsonuntouched (mtime unchanged).Bridge.cfgstays the operator's across three further runs while a hand-edited.csis overwritten every time.--bundle 2026.08.04pins; a nonexistent tag fails with the "every bundle is kept forever" message, exit 1.2for an unrecognized flag,1for an unimplemented command (naming Phase 4 and a manual workaround).Checklist
AI-assisted contributions (required)
Claude Code. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with aCo-Authored-Bytrailer.License