Files
installer/README.md
wtclaude c100d4a2d7
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 5s
ci(bundle): compose and publish the bundle manifest
Phase 0 item 3 of docs/installer/PLAN.md (§7.1-§7.3). The installer resolves
what to install *from* the bundle, so this has to exist before Phase 1 code is
useful. Both components it composes now have releases, which is what unblocked
it.

Adds .gitea/workflows/bundle.yml — resolve both components' latest releases,
run the two compose-time gates, and publish bundles/current.json — plus the
first real bundle (2026.08.04: link v1.1.0 + overlay v0.1.1, protocol 3).

Bundles are COMMITTED under bundles/, not published as releases. This repo's own
releases are the installer binaries, and /releases/latest returns whichever
release is newest regardless of kind, so interleaving bundle releases would make
"latest" intermittently resolve to a release carrying no installer binary. The
push to main needs no new branch-protection exception: release.yml's version-bump
commit already requires it.

Gate 1 (protocol agreement) reads the sidecar's PROTOCOL_VERSION from
sidecar/src/main.rs at the release tag, not from the binary. --print-config
would answer, but only for releases from v1.1.0 on, and --bundle <tag> has to be
able to recompose an older bundle. It also avoids executing a downloaded
artifact and provisioning a throwaway config whose auth token would land in a CI
log. The overlay half comes from manifest.json inside the tarball, which is the
only statement of that version that exists.

Gate 2 (assets) downloads every asset and verifies it against the SHA256SUMS its
publishing repo shipped, then records the hash it computed itself. These
artifacts are deliberately unsigned, so a hash copied from a file nobody checked
would make the whole chain decorative. An asset with no SHA256SUMS entry is
caught separately, since `sha256sum -c` passes right over it.

Release reads are ANONYMOUS on purpose: they are exactly the requests the shipped
installer makes on a host with no Gitea credentials, so a repo flipped to private
fails here rather than on an operator's machine.

Stale components (§7.3) are dispatched, never awaited — Gitea's dispatch endpoint
returns no run handle. "Ahead of its release" counts only releasable commits and
excludes merge commits, whose subject quotes the feat/fix title and would
otherwise re-dispatch a workflow that correctly declines to run, every night.

A run that finds nothing changed writes nothing, comparing everything except
`bundle` and `generated` — that is what makes the nightly cron free rather than a
dated duplicate every morning.

Verified by running the workflow's exact compose steps in a Linux container
against the live releases: both gates pass, the composed bundle is the file
committed here, a re-run reports changed=false, and the stale-detection filter
scores 1 releasable commit for link v1.0.0..main (excluding the merge that quotes
it) and 0 for a docs-only range.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-04 11:10:51 -05:00

115 lines
6.1 KiB
Markdown

# Runic Gateway installer
A single-binary deployment tool that takes a **stock ServUO installation** and
configures it for Runic Gateway: deploys the shard plugin overlay, optionally
applies the stock-file patch tier, installs the uo-link sidecar and registers it
as a service, records what it deployed, and hands the operator the four values
that connect the website to the shard.
```
┌──────────────────────────────────────────┐
│ Runic Gateway installer (>>> HERE <<<)│
└───────────────┬──────────────────────────┘
│ deploys
┌───────────────┴────────────────┐
▼ ▼
ServUO integration uo-link sidecar
overlay sync + opt-in patch tier binary + config + service
(RunicGateway/servuo-plugins) (RunicGateway/link)
```
It is a **deployment tool, not a hosted bootstrapper** — no `curl | bash`, no
installer service. Artifacts are downloaded from a Gitea release page and run.
It also **does not replace ServUO startup behavior.** ServUO keeps running through
its existing release/start scripts; the installer never writes a launcher and
never restarts the shard.
## Status
**Planning — no installer code exists yet.**
The design of record is
[`installer/PLAN.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/installer/PLAN.md)
in the docs repo: phases, locked decisions, and the Phase 0 prerequisites in other
repos (a `servuo-plugins` release workflow, a non-interactive config read-back in
`link`, and the bundle-manifest CI here) that must land before Phase 1 is useful.
All three Phase 0 prerequisites have now landed, so **what the installer will
install already exists and is published**, ahead of the binary that installs it:
[`bundles/current.json`](bundles/current.json) names the current
protocol-checked sidecar + overlay combination, recomposed on every component
release and nightly. See [`bundles/README.md`](bundles/README.md).
Besides that, this repo currently holds its governance documents and issue/PR
templates.
## Related repos
| Repo | What |
|------|------|
| **this**`RunicGateway/installer` | The installer (Rust, one binary per OS). |
| [RunicGateway/link](https://gitea.whitlocktech.com/RunicGateway/link) | The **uo-link sidecar** — the network-facing half of the game bridge. Installed and service-registered by this tool. |
| [RunicGateway/servuo-plugins](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins) | The **C# ServUO plugin** — deployed as source (`overlay/`) and compiled by ServUO at boot. Synced into the server tree by this tool. |
| [RunicGateway/website](https://gitea.whitlocktech.com/RunicGateway/website) | The public site and admin panel. The installer never contacts it — it prints values for Admin → Shard. |
| [RunicGateway/docs](https://gitea.whitlocktech.com/RunicGateway/docs) | All project documentation, including the installer plan. |
## Planned commands
| Command | What it does |
|---|---|
| `install` | Detect and validate the ServUO root, sync the overlay, optionally apply patches, install uo-link + service, write `install.json`, print the token handoff. |
| `doctor` | Diagnose an installed deployment end to end — through to *"has a shard actually dialed in?"*, the only check that distinguishes a working bridge from copied files. |
| `update` | Resolve the current bundle manifest, then update the sidecar (replace + restart) and the overlay (re-sync + tell the operator to restart ServUO). |
| `uninstall` | Remove only what the installer exclusively owns. It **never edits the ServUO tree** — it prints the overlay files to delete and the patch hunks to revert, and leaves that call to the operator. |
## Design constraints worth knowing up front
- **Releases are unsigned.** `SHA256SUMS` is the trust anchor; SmartScreen and
Gatekeeper warnings are expected and documented. The installer nonetheless
verifies the SHA256 of everything *it* downloads and refuses on mismatch.
- **Composition comes from a published bundle manifest**, not from "latest of
each". CI names an exact, protocol-checked combination of sidecar and overlay
versions; `--bundle <tag>` pins one for a reproducible install. A new component
release regenerates JSON, not this binary.
- **The base install must complete without the patch tier.** The patch tier edits
stock ServUO files, most real shards are hand-modified, and unverified ServUO
versions skip it with a warning rather than being patched blind.
- **A successful copy is not a working bridge.** ServUO ignores the script build's
exit code and silently reloads the previous `Scripts.dll`, so diagnostics verify
post-boot state rather than trusting a clean boot.
- **The audience is public** — any ServUO operator, not only shards we run.
## Build & run
Once the crate exists it will be a standard cargo project:
```bash
cargo build --release
cargo run -- --help
```
See [CONTRIBUTING.md](CONTRIBUTING.md) for the development setup, the local
checks CI will run, and the branch/PR workflow.
---
## License
Runic Gateway is free software, licensed under the **GNU General Public License
v3.0 or later** — see [LICENSE.md](LICENSE.md).
Copyright (C) 2026 Runic Gateway
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version. It is distributed WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Contributions are welcome — please read [CONTRIBUTING.md](CONTRIBUTING.md) (note
the **AI-usage disclosure** requirement) and our
[Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities privately per
[SECURITY.md](SECURITY.md).