PLAN: the updater shipped; what is left is where a public download lives

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-23 14:33:20 -07:00
co-authored by Claude Opus 5
parent 68bf3bb218
commit 1599ac65ef
+47 -26
View File
@@ -372,6 +372,32 @@ something long in one, switch away and back, refresh — it's all still there.
a thin line and a name strip on the first level — instead of nested boxes with headers,
which on Linux's single-child folder chains was a staircase of headers around nothing.
Not done: delete from here, a size-over-time history, per-user column choices.
- **Updater** — **shipped 2026-09-23** (`internal/selfupdate`, `internal/api/update.go`,
the Updates card in `Settings.tsx`, `scripts/gitea-release.sh`). A Ham Lab asks one URL
what the newest build is and installs it on request. `update.url` in `config.json` is
either a Gitea/Forgejo repo API base (`…/api/v1/repos/<owner>/<repo>`, whose newest
release names the version and carries the binaries as assets) or any static directory
holding `VERSION`, `SHA256SUMS` and `hamlab-linux-<arch>` — which is exactly what
`make release` writes and what `install.sh` already downloads, so the demo site, a
folder on a NAS and a Gitea release are all the same thing to it. `"off"` never looks.
`update.token` is sent when the source is behind a login, so a **private** Gitea serves
its own fleet without the instance being opened to the world. The binary is verified
against `SHA256SUMS` before it goes anywhere near the running one, then takes the same
path `POST /api/self-update` always did (runs `version`, runs `check` against this
machine's config, atomic replace keeping `hamlab.prev`, re-exec in place) — that path is
now one shared method, `installBinary`. Version ordering is `install.sh`'s `vnum()` rule
ported to Go and tested against it, so the daemon and the installer never disagree about
which of two builds is newer; the commit count since the tag counts, the hash does not.
Checked ~90 s after boot and daily (`update.check: "never"` switches that off), never
installed unasked — an update restarts the daemon and drops open terminals, and the
dialog says so. Settings → **Updates**: installed, published, when it last looked, the
source, the release notes, Check for updates, Install; the rail badges Settings when a
newer build is out (`update_available` rides on `/api/me`). Publishing is
`make gitea-release` → `scripts/gitea-release.sh`, which creates the release and uploads
the five architectures, `SHA256SUMS`, `install.sh` and `VERSION`; it is deliberately
**not** part of `make deploy`, because deploy pushes this build to the machines this hub
owns while publishing offers it to every install anywhere, and one tag per deploy would
be noise. Re-publishing a version needs `--force`.
- **Auth hardening** — WebAuthn passkeys (phone Face ID), TOTP fallback, optional NPM
access list restricting to WireGuard/LAN.
- **Files tab** — **shipped 2026-09-18** (`internal/files`, `Files.tsx`): browse from
@@ -400,32 +426,27 @@ something long in one, switch away and back, refresh — it's all still there.
## To do
- **A public download page, and an updater that uses it** — asked for 2026-09-22, not
started. Today a release is *published* but not *offered*: `make publish` writes five
architectures, `SHA256SUMS`, `VERSION` and `install.sh` into
`/home/core/apps/hamlab-demo/site/dl/` (public at `https://hamlab-demo.bigham.dev`), and
the only way in is `curl -fsSL https://hamlab-demo.bigham.dev/install.sh | sh`. Updating
an existing install is a *hub* pushing its own binary to machines it manages
(`POST /api/self-update`, `hamlab push-nodes`, the Update buttons on the Machines page) —
which does nothing for an install that no hub of mine owns. Two halves:
- **The page.** A human-facing page at the download site: current version and when it was
built, a row per architecture with its size and checksum, the one-line install, and how
to update. Today `/dl/` is a bare directory listing. It should be generated by
`make publish` from the same VERSION and SHA256SUMS the release already writes, so it
cannot drift from the binaries beside it, and it should say plainly that the binaries
are unsigned and served over TLS from my own box.
- **The updater.** A Ham Lab anywhere asks the download site what the current version is,
says so in the UI when it is behind (the About card, and probably a rail badge like
Alerts has), and updates itself on request: fetch the binary for its own architecture,
check it against `SHA256SUMS`, then the same path `POST /api/self-update` already
takes — verify it runs, install atomically, re-exec in place. Decisions to make when it
is built: where the check lives (a `update_url` in `config.json`, defaulting to the
public site, so someone else's install can point elsewhere or switch it off); how often
it asks (daily is plenty, and it must be possible to say never); whether it ever updates
unattended (default no — an update restarts the daemon and drops open terminals); and
whether a hub offers to update its machines from the site when it is itself behind.
Downgrades are already refused by the installer's `vnum()` comparison; the updater
should use the same rule.
- **Somewhere public to download from** — asked for 2026-09-22, half done. The **updater**
shipped 2026-09-23 (above) and reads releases from Gitea, but `git.bigham.dev` runs with
`REQUIRE_SIGNIN_VIEW=true`, so those releases are reachable only with a token. That is
fine for this fleet — each machine carries a read-only `read:repository` token — and no
use at all to a stranger running the `install.sh` one-liner, who still gets the rolling
copy on `hamlab-demo.bigham.dev`. What is left is deciding where a public download
actually lives:
- **Lower the wall on Gitea.** `REQUIRE_SIGNIN_VIEW=false` and per-repo visibility does
the rest: every repo there is private and stays hidden, and only a repo marked public
is visible. That is how Gitea is meant to be configured, and it is the one change that
makes "releases on my Gitea" literally true. It is an instance-wide posture change on
a public hostname, so it is Mitchell's call — the same trade was declined once before
(`docs/docker.md`, the demo site's `install.sh` is hosted outside Gitea for exactly
this reason).
- **Or keep the wall and keep the demo site** as the public face: `make publish` already
writes the rolling `dl/` directory there, and a generated index page (version, built
when, a row per architecture with size and checksum, the one-line install, and that
the binaries are unsigned and served from his own box) would finish the "page" half
without touching Gitea at all.
- Either way the release notes and version history live on Gitea, and the updater does
not care which of the two it is pointed at.
- **Deprecate copyparty** — asked for 2026-09-23, not started. `copyparty` on `grid`
(`copyparty.service`, `:3923`, `/etc/copyparty.conf`, serving all of `/tank` as user