feat(updater): add GitHub Releases source and route felis-api/k3s/cloudflared
Give RoutingSource its second upstream so every non-pinned component now
resolves a real latest-stable: Velocity via PaperMC (already wired), and
felis-api, k3s and cloudflared via the GitHub REST API.
github.go queries /repos/{repo}/releases/latest (one request, rate-limit
friendly) and fails closed: a transport error, a non-200 status (404 = no
stable release), an undecodable body, a draft/prerelease flag, or an
unparseable / prerelease-parsing tag all return an error, never a zero
version. It sends the User-Agent GitHub requires (a UA-less request is
403'd) and tolerates the two live tag styles -- cloudflared's CalVer
"2026.6.1" and k3s's v-prefixed, build-tagged "v1.36.2+k3s1" -- while
String() keeps the raw tag for the report.
source.go routes sourceGitHub to it and drops the errGitHubNotWired stub;
velocity still routes to PaperMC.
Tests: github_test.go covers both tag styles, the User-Agent gate, and
fail-closed on 404 / prerelease-flag / unparseable tag, with fixtures
captured from api.github.com on 2026-07-05. runner_test.go now drives
PaperMC and GitHub through dual httptest servers end to end with no source
degrading to an error.
doc.go re-tiers the verification boundary: both release sources are now
built and live-grounded; the VersionGatherer's version-extraction core is
the next verifiable slice (logic over an exec seam, not pure I/O); the
genuine I/O remainder is the Notifier, Applier and felis update CLI/CronJob.
felis-api's coord is still a placeholder slug, so that component is dark at
runtime until a real repository is configured.
This commit is contained in:
5 files changed
+333
-54
No files matched your search
+27
-23
@@ -10,30 +10,34 @@
|
||||
// Verification boundary — stated honestly so a green test suite is not mistaken for
|
||||
// "the updater works against real infra":
|
||||
//
|
||||
// - BUILT + UNIT-VERIFIED (Go tests, WSL oracle): the topology, the PaperMC Fill
|
||||
// v3 parser, the routing source, and the Runner's report-only composition. The
|
||||
// PaperMC fixture is captured from the live endpoint, and the live call was
|
||||
// exercised out-of-band on 2026-07-04 (curl fill.papermc.io/v3/projects/velocity):
|
||||
// the response shape matches the fixture and 3.4.0 is confirmed the newest stable
|
||||
// (3.5.0-SNAPSHOT correctly filtered). These prove the parse/plan/compose LOGIC
|
||||
// and that the core is now wired to a caller.
|
||||
//
|
||||
// - NOT YET BUILT, but VERIFIABLE HERE (same technique as PaperMC — HTTP GET, JSON
|
||||
// decode, tolerant Parse, prerelease filter, all httptest-testable): the GitHub
|
||||
// Releases source. It is why 3 of the 4 components (felis-api, k3s, cloudflared)
|
||||
// currently report "latest unknown" — RoutingSource returns errGitHubNotWired for
|
||||
// them. This is the next VERIFIABLE slice, not integration remainder; until it
|
||||
// exists the verifiable release-source work is only ~half done.
|
||||
// - BUILT + UNIT-VERIFIED (Go tests, WSL oracle): the topology, BOTH release
|
||||
// sources (PaperMC Fill v3 for Velocity; GitHub Releases for felis-api, k3s and
|
||||
// cloudflared), the routing source, and the Runner's report-only composition. Each
|
||||
// source's parser is a contract test whose fixture is captured from — and whose
|
||||
// live call was exercised out-of-band against — the real endpoint: PaperMC on
|
||||
// 2026-07-04 (3.4.0 is newest stable, 3.5.0-SNAPSHOT filtered), GitHub on
|
||||
// 2026-07-05 (cloudflared 2026.6.1; k3s v1.36.2+k3s1, its "+k3s1"/"v" tolerated and
|
||||
// its "-rcN"/prerelease builds rejected). These prove the parse/plan/compose LOGIC
|
||||
// and that the core is wired to a caller for every tracked component.
|
||||
//
|
||||
// - CAVEATS on what the tests do NOT prove: they run against httptest, not the live
|
||||
// host, so future upstream shape drift is not caught; and while Felis sends a
|
||||
// descriptive User-Agent (PaperMC etiquette), upstream UA enforcement was not
|
||||
// active on the project endpoint on 2026-07-04 (a bare UA got HTTP 200), so the UA
|
||||
// is defensive, not load-bearing.
|
||||
// hosts, so future upstream shape drift is not caught. On User-Agent the two APIs
|
||||
// differ and the code reflects it: GitHub ENFORCES a UA (a bare request is 403'd,
|
||||
// verified 2026-07-05) so Felis's UA is load-bearing there; PaperMC does NOT
|
||||
// enforce (a bare request got HTTP 200 on 2026-07-04) so its UA is only etiquette.
|
||||
// Also: felis-api's topology coord "felis/felis" is a PLACEHOLDER slug — the GitHub
|
||||
// routing/parse logic is verified, but that one component stays dark at runtime (its
|
||||
// Latest errors, degrading to "latest unknown") until a real repository is configured.
|
||||
//
|
||||
// - REMAINING INTEGRATION (pure I/O, no verifiable-here logic): the concrete
|
||||
// VersionGatherer (`k3s --version`, image-tag / jar inspection), the concrete
|
||||
// Notifier (SMTP + in-game) and Applier (control-plane image bump, cloudflared
|
||||
// swap), the `felis update` CLI + CronJob entry point, and the runtime append of
|
||||
// the live Pinned Minecraft fleet.
|
||||
// - NOT YET BUILT, but VERIFIABLE HERE (the next slice): the VersionGatherer's
|
||||
// extraction core — command output (`k3s --version`), image tag
|
||||
// (`rancher/k3s:v1.36.2-k3s1`) or jar filename → Version. That is logic over an
|
||||
// exec/read seam, testable with a fake runner à la internal/reaper's ExecRunner,
|
||||
// and load-bearing: a mis-read current version makes every plan wrong (spurious
|
||||
// applies or missed upgrades). Only the seam's actual I/O is un-verifiable here.
|
||||
//
|
||||
// - REMAINING INTEGRATION (genuinely I/O-bound — needs a cluster/mailbox to exercise):
|
||||
// the concrete Notifier (SMTP + in-game) and Applier (control-plane image bump,
|
||||
// cloudflared swap), the `felis update` CLI + CronJob entry point, and the runtime
|
||||
// append of the live Pinned Minecraft fleet.
|
||||
package updater
|
||||
Reference in new issue
Block a user