Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions projects/ProvinceSystem/DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Deploys to the same site run one at a time.
cannot read).
5. Waits up to 3 minutes for both health checks. If they fail, it puts the previous commit back, rebuilds and checks
again, then exits 5. It never restores the database; restore a backup by hand if a migration needs undoing.
6. After a healthy www deploy that changes `backend/src/patchnotes/`, runs `sudo tfmc-patchnotes-update <sha>` so the
[patch note jobs](docs/ops/patch-notes-jobs.md) use the same code. A failure there is logged and does not fail the
deploy.

Each run appends a line to `~/site-deploy.log`.

Expand Down
1 change: 1 addition & 0 deletions projects/ProvinceSystem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](..
- [Rail network](docs/integrations/rail.md)
- [Server plugin versions and restart controls](docs/integrations/servers.md)
- [Database studio](docs/ops/database-studio.md)
- [Patch note host jobs](docs/ops/patch-notes-jobs.md)
- [Patreon integration](docs/integrations/patreon.md) and [backend protocol](docs/integrations/patreon-backend.md)
- [Kit default skins](backend/assets/kit_skins/README.md)
- [Map regeneration benchmarks](backend/benchmarks/regen/README.md)
Expand Down
1 change: 1 addition & 0 deletions projects/ProvinceSystem/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This section is the product and technical reference for **ProvinceSystem**. Tech
5. [ops/sheet-render.md](ops/sheet-render.md) - 3D review-sheet renderer (prod deploy + smoke)
6. [ops/dev-config.md](ops/dev-config.md) - dev-only flags and shortcuts
7. [ops/diagnostic.md](ops/diagnostic.md) - player diagnostic page and staff reports
8. [ops/patch-notes-jobs.md](ops/patch-notes-jobs.md) - patch note jobs on the TF server

Schema assets: [assets/map-export-schema.json](assets/map-export-schema.json) (SF map export contract).

Expand Down
55 changes: 55 additions & 0 deletions projects/ProvinceSystem/docs/ops/patch-notes-jobs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Patch note host jobs

Three systemd units on the TF server feed the patch notes on `www.tfminecraft.net`. They call www's API on
`127.0.0.1:8000` with the staff key from `/etc/tfmc/patchnotes.env` (root, mode 600, `STAFF_KEY` and
`API_BASE_URL`), and run a root-owned copy of
[`backend/src/patchnotes`](https://github.com/TF-Minecraft/ProvinceSystem/tree/main/backend/src/patchnotes), never the
site checkout.

| Unit | Runs | As | Sees |
| --- | --- | --- | --- |
| `tfmc-patchnotes-watch.timer` | `patchnotes.watch_plugins --once` every ten minutes | throwaway user (`DynamicUser`) | Main's `plugins` folder, read-only; state in `/var/lib/tfmc-patchnotes/` |
| `tfmc-patchnotes-weekly.timer` | `patchnotes.weekly_run` every ten minutes, offset by five | throwaway user | Main's `Backups` folder, read-only |
| `tfmc-patchnotes-rewrite.service` | `patchnotes.rewrite_worker`, always on | root | the Codex CLI and its login in `/root`; no `/home`, no Docker |

The watcher holds `CAP_DAC_READ_SEARCH` because some plugin files are `amp`'s and mode 600, so it can read any file
it can see. Its `/home` holds only the plugin folders and its `/var/lib` only its own state; the rest of the system is
read-only, with `/etc/shadow`, `/etc/ssh`, `/etc/ssl/private`, `/etc/tfmc`, the Docker socket and the logs hidden. The
weekly job has no extra rights: the backup zips are world-readable. Both time out after 30 minutes. The rewrite worker
stays root because the Codex login it uses belongs to root.

## Updating the code

The copies live in `/usr/local/lib/tfmc-patchnotes/<commit>/patchnotes/`, and `current` points at the one in use.
`site-deploy` installs a new copy after a www deploy that changes `backend/src/patchnotes/`. By hand:

```bash
sudo tfmc-patchnotes-update <full commit on main>
```

[`tfmc-patchnotes-update`](https://github.com/TF-Minecraft/ProvinceSystem/blob/main/scripts/patchnotes-update.py)
refuses commits that are not on `main` or have no passing **Build**, and commits that change the updater or any of
the five unit files: install those by hand as below. It downloads the package's modules from GitHub (tests are left
out; any other file or folder in the package is refused), restarts the rewrite worker and needs it to stay up with the
same process for 20 seconds. Otherwise it puts the previous copy back, or stops the worker if there was none. The
timers pick up the new copy on their next run. It keeps the five newest copies and logs to
`/var/log/tfmc-patchnotes-update.log`; `site-deploy` also records a failed update in its own log.

## Installing

From a ProvinceSystem checkout, as root:

```bash
install -m 600 /dev/null /etc/tfmc/patchnotes.env # then set STAFF_KEY=... and API_BASE_URL=...
install -m 755 scripts/patchnotes-update.py /usr/local/sbin/tfmc-patchnotes-update
cp scripts/tfmc-patchnotes-*.service scripts/tfmc-patchnotes-*.timer /etc/systemd/system/
systemctl daemon-reload
tfmc-patchnotes-update <full commit on main>
systemctl enable --now tfmc-patchnotes-rewrite tfmc-patchnotes-watch.timer tfmc-patchnotes-weekly.timer
systemctl start tfmc-patchnotes-watch tfmc-patchnotes-weekly # one run of each, to check
```

The account that runs `site-deploy` needs `NOPASSWD` sudo for `/usr/local/sbin/tfmc-patchnotes-update`. After a
change to the updater or a unit, repeat the `install`/`cp` lines and `systemctl daemon-reload` before updating.

Check them with `systemctl list-timers 'tfmc-patchnotes-*'` and `journalctl -u 'tfmc-patchnotes-*'`.