minecraft-server/docs/ROADMAP.md

172 lines
6.9 KiB
Markdown
Raw Normal View History

# Roadmap — plugin acquisition overhaul
Goal: replace runtime env-driven plugin downloads with a reproducible, source-of-truth-first acquisition pipeline. Make the server fully open source, fully auditable, fully reproducible.
## Problem (current state)
Plugins are pulled at every container boot via `MODRINTH_PROJECTS` + `SPIGET_RESOURCES` env vars in `docker-compose.yml`. Pain points hit during 2026-04-27 deploy:
- **Slug ≠ name** — `vault`, `protocollib` not on Modrinth at expected slug. Three boot loops to discover.
- **Channel mismatch** — GrimAC alpha-only, WorldEdit beta-only on bleeding-edge MC versions. Default `release` filter silently rejected. Two more boot loops.
- **Wrong env var** — `MODRINTH_DEFAULT_VERSION_TYPE` is for modpack flow; `MODRINTH_PROJECTS` flow needs `MODRINTH_PROJECTS_DEFAULT_VERSION_TYPE`. One more boot loop.
- **VERSION=LATEST + Purpur** — Purpur 26.x versioning scheme confused itzg, sent "26.1.2" as MC version to Modrinth API; EssentialsX query returned no files.
- **No lockfile** — `latest` drifts daily. No checksum, no audit trail.
- **No pre-flight** — every typo is a 30s container restart cycle.
- **License opacity** — no automated check that plugins are FOSS-compatible before adding.
- **`REMOVE_OLD_MODS=*.jar`** wipes manually-placed jars on every boot, hostile to manual-only plugins (LoginSecurity, MarriageMaster, etc).
## Acquisition order — proposed
1. **GitHub Releases** (primary)
2. **Hangar** (PaperMC official)
3. **Modrinth**
4. **Spiget / SpigotMC**
5. **Manual jar** (last resort, premium/dead)
### Why GitHub first
- Source-truth: jar built from tag, signed commit, reproducible.
- License visible — repo `LICENSE` file. FOSS audit trivial.
- Stable URL pattern: `github.com/<owner>/<repo>/releases/download/<tag>/<asset>.jar`.
- API: `api.github.com/repos/<owner>/<repo>/releases/latest` — JSON, version + asset URLs + checksums.
- No platform lock-in (Modrinth/Hangar can delist; GH source survives).
- Most Bukkit plugins ARE on GitHub — Modrinth/Hangar often just mirror.
## Design
### `plugins.yml` (manifest, committed)
```yaml
plugins:
- name: LuckPerms
sources:
- github: { owner: LuckPerms, repo: LuckPerms, asset_pattern: "LuckPerms-Bukkit-*.jar" }
- modrinth: luckperms
pin: latest # or "5.5.20" or sha256:abc...
- name: ProtocolLib
sources:
- github: { owner: dmulloy2, repo: ProtocolLib, asset_pattern: "ProtocolLib.jar" }
- spiget: 1997
- name: Vault
sources:
- github: { owner: MilkBowl, repo: Vault, asset_pattern: "Vault.jar" }
- name: WorldEdit
sources:
- github: { owner: EngineHub, repo: WorldEdit, asset_pattern: "worldedit-bukkit-*.jar" }
- hangar: { author: EngineHub, project: WorldEdit }
- modrinth: worldedit
channel: beta
- name: LandClaimPlugin
sources:
- modrinth: landclaimplugin
- name: LoginSecurity
sources:
- manual: ./manual-jars/LoginSecurity-3.3.1.jar
license: GPL-3.0
upstream_url: https://www.spigotmc.org/resources/loginsecurity.19362/
```
### `plugins.lock` (generated, committed)
```
LuckPerms-Bukkit-5.5.20.jar sha256:abc... github:LuckPerms/LuckPerms@v5.5.20
ProtocolLib.jar sha256:def... github:dmulloy2/ProtocolLib@5.4.0
...
```
### `scripts/fetch-plugins.sh` (resolver)
Runs **before** `docker compose up`. Pseudo:
```bash
for plugin in plugins.yml; do
for src in plugin.sources; do # fallback chain — first hit wins
case src.type in
github) asset=$(gh-api releases/latest); curl -L -o $asset ;;
hangar) curl hangar.papermc.io/api/v1/projects/... ;;
modrinth) curl api.modrinth.com/v2/project/$slug/version ;;
spiget) curl api.spiget.org/v2/resources/$id/download ;;
manual) cp $path ;;
esac
[ $? -eq 0 ] && break
done
sha256sum $jar >> plugins.lock
done
```
Output: `plugins/*.jar` directory ready to bind-mount, plus `plugins.lock` for diff/audit.
### Compose changes
```yaml
volumes:
- /opt/docker/minecraft:/data
environment:
REMOVE_OLD_MODS: "false" # plugins/ pre-populated, don't wipe
# delete: MODRINTH_PROJECTS, SPIGET_RESOURCES, MODRINTH_PROJECTS_DEFAULT_VERSION_TYPE
```
itzg image becomes pure runtime. Plugin acquisition is a separate, testable, reproducible build step.
## Phased rollout
### Phase 1 — pin everything (1 hour)
Keep itzg env-driven. Replace `slug` with `slug:VERSION_ID` in `MODRINTH_PROJECTS`. Use `id:VERSION` in `SPIGET_RESOURCES`. No more `latest` drift.
**Acceptance:** `docker compose up -d` produces identical plugin set on any host, any day.
### Phase 2 — fetch script + manifest (1 day)
- Write `plugins.yml` w/ all current plugins + sources.
- Write `scripts/fetch-plugins.sh` (bash, jq, curl, gh CLI).
- Write `plugins.lock` first run, commit it.
- Strip `MODRINTH_PROJECTS`/`SPIGET_RESOURCES` from compose; `REMOVE_OLD_MODS: false`.
- Document new deploy: `./scripts/fetch-plugins.sh && docker compose up -d`.
**Acceptance:** plugins/ populated from GH-first, lock committed, deploy reproducible.
### Phase 3 — CI automation (1 day)
- GH Action daily: `fetch-plugins.sh --check-updates` → open PR per update, body has changelog link.
- GH Action per-PR: license audit (`/repos/{owner}/{repo}/license` → SPDX id → `LICENSES.md`).
- Renovate-style auto-merge for patch updates (config-gated).
**Acceptance:** plugin updates land via PR, license audit in CI, no manual fetches.
## Tooling to evaluate first
| Tool | Status | Verdict |
|------|--------|---------|
| `mcpkg` | exists, immature | reuse if active |
| `packwiz` | mod-focused, Modrinth/Curse | adapt? |
| `paper-plugin-manager` | Hangar client | use as Hangar source |
| Custom bash + jq + gh + curl | trivial to build | likely fastest |
Probably 200 lines of bash beats adopting an unmaintained tool.
## Side benefits
- **License audit** — generated `LICENSES.md` proves the stack is FOSS.
- **Pre-flight** — `fetch-plugins.sh --check` validates manifest in CI before merge, no boot-time surprise.
- **Offline deploy** — pre-baked `plugins/` dir + tarball = air-gap deploy possible.
- **Forks** — easy to swap `LandClaimPlugin` upstream → your own fork by changing one line in `plugins.yml`.
## Open questions
- License whitelist policy: GPL-3, MIT, Apache-2 OK? AGPL? Proprietary?
- Update cadence: daily auto-PR, weekly, manual?
- Pin granularity: per-plugin tag, sha256 hash, or commit SHA?
- Failure mode if a source delists a pinned version: pin migration script?
- Manual-jar storage: in-repo `manual-jars/` (license risk) or separate private repo?
## Status
- 2026-04-27 — roadmap drafted post-deploy painshare. Not started.
- 2026-04-28 — Phase 1 (pin versions) still pending. `REMOVE_OLD_MODS` bug discovered: itzg disables it when `PLUGINS` env set, so manual jars are safe. Phase 2 design finalized here. No code yet.