From 6b7e90765fbcd5278e7cf0225d0e549f07d6eb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Tue, 6 Oct 2026 15:08:33 +0200 Subject: [PATCH] R1 plan: updates from Gitea, the design round (Q162-Q174) Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- docs/milestones/R1.md | 48 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/milestones/R1.md b/docs/milestones/R1.md index fe9bfa8..1636a17 100644 --- a/docs/milestones/R1.md +++ b/docs/milestones/R1.md @@ -1,6 +1,6 @@ # R1 — Releases -**Status:** in progress. CI and signed releases on Gitea (issue #5) are in place since 2026-10-06: every tag from v0.1.0 to v0.10.0 has its release. Next: updates from Gitea (#6), which waited for this, and the Issues App (#4). +**Status:** in progress. CI and signed releases on Gitea (issue #5) are in place since 2026-10-06: every tag from v0.1.0 to v0.10.0 has its release. Updates from Gitea (issue #6) is being built, locally, on branch `gitea-updates`. The Issues App (#4) comes after. **Goal:** a tag is a release, built the same way every time and published where a device can find it. @@ -40,3 +40,49 @@ Until now the tests, the builds, the signing and the flashing all happened on on - **The runner's label took three tries.** Registered as `ubuntu://docker:ubuntu:resolute` and then as `ubuntu::docker://...`, Gitea took the whole string for the label's name; with the first, jobs ran on the runner's host itself. The first version of the workflow was written for that (plain shell, `docker run` for the build) and published v0.10.0 that way. `ubuntu:docker://docker.gitea.com/runner-images:ubuntu-latest` is the form that works. - **Gitea 1.27's API can't cancel a run that isn't finished**, only delete a finished one; switching Actions off and on for the repository doesn't either. Runs queued for a label that no longer exists stay queued until cancelled in the web UI. - **CI's image isn't byte-identical to a local build of the same tag** (same size, different bytes). Not pursued (Q158). + +## Updates from Gitea (issue #6) + +The device looks at the project's Gitea for a newer release, says so, and installs it on request, with the same signed Update Files, Probation and rollback as a push from the PC or an install from the card. + +### What the server gives (checked 2026-10-06) + +- **Its certificate** is Let's Encrypt, all ECDSA: leaf `git.twis.la` (renewed every few months, next expiry 2026-12-14) under the intermediate YE2, Root YE and ISRG Root X2, which X1 cross-signs. Pinning the leaf would ask a question at every renewal. +- **The API** answers over HTTP/1.1, chunked: `releases/latest` is 3.2 KB (about 350 bytes of it matter), a list of ten releases is 33 KB. +- **A download** is a direct 200 with `Content-Length` and no redirect; ranges work. + +### Decisions (design round 2026-10-06) + +| # | Decision | +|---|---| +| Q162 | **Trust:** the firmware carries ISRG Root X1 and X2 and checks the server's chain and name against them, not the framework's bundle of about 130 CAs. Shared with #4. If the server moves to another CA, the next firmware comes from the PC. | +| Q163 | The Update File's own signature stays the real guard. A hijacked connection could hide a release or offer an older signed one, never install firmware that isn't ours. | +| Q164 | The source, `git.twis.la` and `twisla/roro9stack`, is a constant in the firmware. A fork changes it, and has its own key. | +| Q165 | **When:** on request in Settings > Firmware, and once a day in the background while Wi-Fi is up and the Clock is set (certificate dates need it). A setting, **Check for updates**, on by default. It installs nothing by itself; it skips quietly below the memory floor and never runs during an install. | +| Q166 | A Toast, "Update v0.11.0 available: see Settings > Firmware", once per version per boot. | +| Q167 | **The download goes straight into the inactive slot,** no card needed. A truncated or tampered file is refused after 160 bytes or at its end, and the running firmware is untouched. A failed download starts over. | +| Q168 | A version that failed (rolled back) isn't announced again by the background check until a newer one exists; it can still be installed by hand. | +| Q169 | **Older releases:** a list of the last ten, newest first, the running one marked. Installing an older one asks with a stronger warning. | +| Q170 | Enter on a release shows its version, date, size and the tag message, with Install. | +| Q171 | **Debug Builds** check and show the latest release, but don't install it: it would replace the Debug Build and its console (Q153: Debug Builds aren't published). Their updates come from the PC. | +| Q172 | The memory floors of Q86: no check or download below 55 KB free. | +| Q173 | Left out, each with its issue: installing automatically (#52), a release channel (#53), resuming a download (#54). | +| Q174 | Ships as **v0.11.0**. Tested on the device with the real signed releases; a Debug Build command pretends the device runs an older version, so v0.10.0 counts as an update. | + +### Done when + +- A check, by hand or daily, tells the right thing: up to date, newer available, no network, bad certificate, no clock, too little memory. +- A newer release installs from the Firmware page with no card and no PC, and the device restarts into it and confirms it. +- A tampered or truncated download is refused and the running firmware keeps running. +- The Older releases list shows ten, and installing one asks first. +- A release that rolled back isn't announced again. +- A Debug Build shows the latest release and doesn't install it. +- The daily check never runs below the memory floor, during an install, or without a clock. + +### Work breakdown + +1. **Model** (host-tested): a streaming JSON scanner, the release list read from it, HTTP response heads and chunked bodies, URLs, which release counts as an update. +2. **The connection:** the root certificates, an HTTPS client, a check and a list from the Update Service's task; console commands to try them. +3. **The download:** an HTTPS source for the existing install path. +4. **The screens:** the Firmware page's release rows, the release page, Older releases, the setting, the daily check and its Toast. +5. **Checks on the device**, recorded here.